Home > Net >  Listen to token being removed from local storage and update state
Listen to token being removed from local storage and update state

Time:12-30

I'm connecting user authorization with the backend. When I receive accessToken, I store it in local storage. When it expires, I remove it from local storage.

Saving and removing from local storage happens in my service file, and the below code is a part of my context file from which I manage my global session state.

The first useEffect keeps the user logged in when the page is reloaded. In the second one, I wanted to automatically log the user out whenever one of the endpoints returns 401 unauthorized (so when accessToken is removed from local storage).

However, the second one does not reload when the token is removed. Even if I put there a console.log, it doesn't show up in the console. It just doesn't even run.

Why is useEffect not reacting to local storage item change?

const [sessionState, setSessionState] = useState<SessionStateType>({
    status: "anon",
    accessToken: null,
});

useEffect(() => {
    const token = localStorage.getItem("accessToken");
    if (token) {
      setSessionState({ status: "auth", accessToken: token });
    }
  }, []);

  const token = localStorage.getItem("accessToken");

  useEffect(() => {
    if (!token) {
      setSessionState({ status: "anon", accessToken: null });
    }
  }, [token]);

CodePudding user response:

There is no listening to local storage changes in your code, and it's not the behavior by default. And even if it was the case, you need to somehow re-render your component to have your useEffect with token as a dependency to re-run.

A solution is to set up an event listener for storage in your useEffect, and remove that token that's outside, like so:

// const token = localStorage.getItem("accessToken");
useEffect(() => {
  // on page load
  const token = localStorage.getItem("accessToken");
  if (!token) {
    setSessionState({ status: "anon", accessToken: null });
  }

  // when the storage change
  window.addEventListener("storage", () => {
    const token = localStorage.getItem("accessToken");
    if (!token) {
      setSessionState({ status: "anon", accessToken: null });
    }
  });
}, []);

But for this event to run, anytime you clear the storage, immediately call a dispatchEvent like so:

localStorage.removeItem("accessToken");
window.dispatchEvent(new Event("storage"));

That last step is needed because storage event works this way:

The storage event of the Window interface fires when a storage area (localStorage) has been modified in the context of another document.

So this dispatchEvent is needed as we need to listen to changes in the same document as well.

  • Related