Search code examples
javascriptreactjsclosures

Not getting the updated pathname value inside the eventListener


I'm adding a scroll event listener to the effect, so that when a certain section is reached, the url changes to a different one.

React.useEffect(() => {
  window.addEventListener('scroll', handleScroll);

  return () => {
    window.removeEventListener('scroll', handleScroll);
  };
}, [])

Here's the function handleScroll

const handleScroll = () => {
  const urlKey = `/${section}/${url}`;

  if (pathname !== urlKey) {
    history.replace(urlKey);
  }
}

The values for section and url are taken elsewhere, and they are output correctly. The problem is that inside handleScroll pathname is always the same. I don't understand how to fix it. Please give me a hint.


Solution

  • Try to wrap the handleScroll function in useCallback, which will create a new instance of the function whenever one of the dependencies (section, url, pathname) changes:

    const handleScroll = React.useCallback(
      () => {
        const urlKey = `/${section}/${url}`;
    
        if (pathname !== urlKey) {
          history.replace(urlKey);
      },
      [section, url, pathname]
    );
    

    Then, add the callback to the dependencies of useEffect to update the event listener whenever there is a new instance of handleScroll:

    React.useEffect(
      () => {
        window.addEventListener('scroll', handleScroll);
    
        return () => {
          window.removeEventListener('scroll', handleScroll);
        };
      }, 
      [handleScroll]
    );