Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

useEffect doesn't update state on route change

I am looking for a solution to register the route change and apply new state using setState and useEffect. The current code below doesn't update functions of setState when the route is changed.

For example, I register the pathname of / with location.pathname === '/' within createContext, if the pathname is / the setState of isHome is registered true, however if pathname is /page-1 setState is registered false.

On browser reloads, onMount the state is correctly set, however on a route change using Link this does not. Also, please note that I am using Gatsby and in doing so, importing { Link } from 'gatsby'

CreateContext.js

export const GlobalProvider = ({ children, location }) => {


const prevScrollY = useRef(0);
  const [state, setState] = useState({
    isHome: location.pathname === '/',
    // other states
  });

  const detectHome = () => {
    const homePath = location.pathname === '/';
    if (!homePath) {
      setState(prevState => ({
        ...prevState,
        isHome: false
      }));
    }
    if (homePath) {
      setState(prevState => ({
        ...prevState,
        isHome: true
      }));
    }
  };

  useEffect(() => {
    detectHome();
    return () => {
      detectHome();
    };
  }, [state.isHome]);

  return (
    <GlobalConsumer.Provider
      value={{
        dataContext: state,
      }}
    >
      {children}
    </GlobalConsumer.Provider>
  );
};

If I console.log(state.isHome) on pathname / I get true, any other pathnames I get false, however, if I change route, the current isHome state remains previous, until I scroll and useEffect applies.

The point of registering the isHome state is to alter CSS per page.

How can I update state with useEffect when changing route. Previously, I would have done this with componentDidUpdate and register prevProps.location.pathname against props.location.pathname, however, my understanding is that this is no longer necessary with the useEffect hook.

like image 500
Darren Avatar asked Sep 25 '19 12:09

Darren


People also ask

Does useEffect run on state change?

Use the useEffect hook to listen for state changes in React. You can add the state variables you want to track to the hook's dependencies array and the logic in your useEffect hook will run every time the state variables change.

Is useEffect synchronous or asynchronous?

The useLayoutEffect function is triggered synchronously before the DOM mutations are painted. However, the useEffect function is called after the DOM mutations are painted. I chose this example to make sure the browser actually has some changes to paint when the button is clicked, hence the animation.

Does useEffect run sequentially?

IMPORTANT: After the component is done rendering, it checks each useEffect hook sequentially in order which they are written. Going through each useEffect hook in the component (that has done rendering). If any of the entry in the dependency array has changed, the callback associated with it/passed to it is run.

Can I use async in useEffect?

Either way, we're now safe to use async functions inside useEffect hooks. Now if/when you want to return a cleanup function, it will get called and we also keep useEffect nice and clean and free from race conditions. Enjoy using async functions with React's useEffect from here on out!


1 Answers

The effect you want is "When the location change then update my state", this is translated in useEffect code like this :

  useEffect(() => {
    detectHome();
    return () => {
      detectHome();
    };
  }, [location]);
like image 200
Mohamed Ramrami Avatar answered Oct 10 '22 22:10

Mohamed Ramrami