Home > Blockchain >  React, listen for localStorage changes with a custom hook accros different components
React, listen for localStorage changes with a custom hook accros different components

Time:05-26

I have a custom hook to manage localStorage like below:

import { useEffect, useState } from 'react'

export default function useLocalStorage(key, initValue) {

    const [state, setState] = useState(() => {
        const value = localStorage.getItem(key);
        if (value !== null) {
            return JSON.parse(value);
        }

        localStorage.setItem(key, JSON.stringify(initValue));
        return initValue;
    })

    useEffect(() => {
        localStorage.setItem(key, state);
    }, [key, state])
    
    return [state, setState];
}

This custom hook is declared to use the same localstorage key for two or more components in one screen. e,g.

const [state, setState] = useLocalStorage('key', false);

At this time, since components using useLocalStorage want to work according to the state change of localStorage, we try to use the state returned by useLocalStorage as the second parameter of useEffect.

useEffect(() => {
   foobar()
}, [state]);

I expected the foobar() function in useEffect to work when the "state" changes in all components that declared this useEffect. However, foobar() only worked for one component out of several components using this same useEffect.Why this is happening? How do I get it to work the way I want it to?

CodePudding user response:

You should listen the local storage changes in order to have the updated value. For example this way:

import { useEffect, useState } from 'react'

export default function useLocalStorage(key, initValue) {
  const [state, setState] = useState(() => {
    const value = localStorage.getItem(key);
    if (value !== null) {
      return JSON.parse(value);
    }

    localStorage.setItem(key, JSON.stringify(initValue));
    window.dispatchEvent(new Event("storage");
    return initValue;
  });

  useEffect(() => {
    localStorage.setItem(key, state);
    window.dispatchEvent(new Event("storage");
  }, [key, state]);

  useEffect(() => {
    const listenStorageChange = () => {
      setState(() => {
        const value = localStorage.getItem(key);
        if (value !== null) {
          return JSON.parse(value);
        }

        localStorage.setItem(key, JSON.stringify(initValue));
        window.dispatchEvent(new Event("storage");
        return initValue;
      });
    };
    window.addEventListener("storage", listenStorageChange);
    return () => window.removeEventListener("storage", listenStorageChange);
  }, []);

  return [state, setState];
}
  • Related