skip to Main Content

I am trying to build a global navigation system for my react app where I store the states in local storage and url. now when I need to go back, the first time when I click back it works. I restore the previous states. But from next back click i have to do it twice before I can go back to the previous state. the history is not updating on the first back click. the url is also not changing on first click.

my code is as follows –

const useMyHook = (key) => {

  const [st1, setSt1] = useState(null);
  const [st2, setSt2] = useState(null);
  const [initialLoad, setInitialLoad] = useState(true); // to find if it is loaded

  useEffect(() => {

    const storedFilters = JSON.parse(localStorage.getItem(key));
    if (storedFilters && initialLoad) {
      setSt1(storedFilters.st1);
      setSt2(storedFilters.st2);
    }
    setInitialLoad(false); // once loaded set it to false
  }, [initialLoad, key]);

  useEffect(() => {
    const updateQueryParams = () => {
      const queryParams = new URLSearchParams();
      if (st1) queryParams.set('state1', st1);
      if (st2) queryParams.set('state2', st2);
      const queryString = queryParams.toString();
      const newUrl = `${window.location.pathname}?${queryString}`;

      window.history.pushState({ path: newUrl }, '', newUrl);
      localStorage.setItem(key, JSON.stringify({ st1, st2 }));
    };
    updateQueryParams();
  }, [st1, st2, key]);


  useEffect(() => {

    const handlePopState = () => {
      const queryParams = new URLSearchParams(window.location.search);
      setApps(queryParams.get('state1') ? parseInt(queryParams.get('state1')) : null);
      setLoc(queryParams.get('state2') ? parseInt(queryParams.get('state2')) : null);
    };


    window.addEventListener('popstate', handlePopState);

    return () => {
      window.removeEventListener('popstate', handlePopState);
    }
  }, []);


  return { st1, setSt1, st2, setSt2 };
};

2

Answers


  1. I believe this is happening because your app is running in strict mode:

    StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them (which can be quite useful).

    you can put an if to make sure that this combination of dependencies is new
    or you can fix your logic so you don’t use useEffect other than when interacting with external systems. Read this from the official docs for more information: You Might Not Need an Effect

    hope this might help!

    Login or Signup to reply.
  2. The issue you’re experiencing may be related to how you’re handling the initialLoad state in your useMyHook custom hook. It seems that the first time you click the back button, the initialLoad state is set to false, and subsequent clicks work as expected. However, on subsequent visits to the page, the initialLoad state is set to true again, causing the initial state to be restored.

    To resolve this issue, you can modify your code as follows:

    const useMyHook = (key) => {
      const [st1, setSt1] = useState(null);
      const [st2, setSt2] = useState(null);
      const [initialLoad, setInitialLoad] = useState(true); // to find if it is loaded
    
      useEffect(() => {
        const storedFilters = JSON.parse(localStorage.getItem(key));
        if (storedFilters) {
          setSt1(storedFilters.st1);
          setSt2(storedFilters.st2);
        }
        setInitialLoad(false); // set it to false regardless of storedFilters existence
      }, [key]);
    
      // Rest of your code...
    };
    

    In this updated code, the initialLoad state is set to false as soon as the component mounts, regardless of whether there are stored filters in the localStorage or not. This ensures that subsequent visits to the page won’t trigger the restoration of the initial state.

    Additionally, the initialLoad dependency has been removed from the first useEffect hook because it’s not necessary to include it there. The effect only needs to run once, regardless of the initialLoad state.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search