skip to Main Content

Sorry about another one of these but I’m at a loss. I am adding an event listener inside of useEffect(). The event fires (console.log() prints as expected) but the state isn’t getting updated. Could someone please explain to me what’s going on here and how to solve this problem? Thanks!

const [loading, setLoading] = useState({ message: "", progress: 0 });

  useEffect(() => {
    function handleProgress(e: ProgressEvent<EventTarget>) {
      console.log(e.loaded);
      setLoading({message: "Processing Data", progress: e.loaded});
    }

    document.addEventListener("progress", handleProgress);
    return () => {
      document.removeEventListener("progress", handleProgress);
    };
  }, []);

2

Answers


  1. State behaves like snapshot. The set function only updates the state variable for the next render. If you read the state variable after calling the set function, you will still get the old value that was on the screen before your call.

    you may check it using html like <span>{loading}</span>.

    Ref: React useState documentation
    React state Snapshot documenation

    Login or Signup to reply.
  2. The reason for this behavior is that the event listener function handleProgress captures the initial state of loading when it is defined. Therefore, when setLoading is called inside handleProgress, it is using the initial state and not the updated state.

    To solve this problem, you can utilize the functional form of setLoading provided by React’s useState hook. This form of setLoading allows you to update the state based on the previous state.

    Here is the code to correctly update the state based on the previous state:

    const [loading, setLoading] = useState({ message: "", progress: 0 });
    
    useEffect(() => {
      function handleProgress(e: ProgressEvent<EventTarget>) {
        console.log(e.loaded);
        setLoading(prevLoading => ({
          ...prevLoading,
          message: "Processing Data",
          progress: e.loaded
        }));
      }
    
      document.addEventListener("progress", handleProgress);
      return () => {
        document.removeEventListener("progress", handleProgress);
      };
    }, []);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search