useContext not updating its value in callback

Viewed 3612

useConext value is not updating in my callback attached to wheel event. I tried to console but still printing static value. But outside the callback, it's printing updated value

const Home = () => {
  //accessing my context
  var [appState, dispatch] = useContext(CTX);
  //printing updated value here (working perfect here)
  console.log(appState);

  //my callback on wheel event (also using debouce to queue burst of events)
  var fn = debounce(e => {
    //incrementing value ++1
    dispatch({ type: 'INCREMENT_COMPONENT_COUNTER' });
    //printing static value here (problem here)
    console.log(appState);
  }, 500);

  //setting and removing listener on component mount and unmount
  useEffect(() => {
    window.addEventListener('wheel', fn);
    return () => {
      window.removeEventListener('wheel', fn);
    };
  }, []);
};
2 Answers

On mounting, the listener initialized with a function variable which encloses the first value of appStore in its lexical scope.

Refer to Closures.

To fix it, move it into useEffect scope.

const Home = () => {
  const [appState, dispatch] = useContext(CTX);

  useEffect(() => {
    const fn = debounce(e => {
      dispatch({ type: 'INCREMENT_COMPONENT_COUNTER' });

      console.log(appState);
    }, 500);

    window.addEventListener('wheel', fn);
    return () => {
      window.removeEventListener('wheel', fn);
    };
  }, [appState]);
};

Friendly advice:

Your debance function is changing in every render, while the useEffect have the capture of only the first render, you can fix this with a useCallback:

const Home = () => {
  // accessing my context
  const [appState, dispatch] = useContext(CTX)
  // printing updated value here (working perfect here)
  console.log(appState)

  // my callback on wheel event (also using debouce to queue burst of events)
  const fn = useCallback(
    () =>
      debounce(e => {
        // incrementing value ++1
        dispatch({ type: 'INCREMENT_COMPONENT_COUNTER' })
        // printing static value here (problem here)
        console.log(appState)
      }, 500),
    [appState, dispatch],
  )

  // setting and removing listener on component mount and unmount
  useEffect(() => {
    window.addEventListener('wheel', fn)
    return () => {
      window.removeEventListener('wheel', fn)
    }
  }, [fn])
}
Related