Skip to content

Home

Persisting state in React

Sometimes, you might want to persist the state of your React components across page reloads. You can achieve this by using the localStorage or sessionStorage APIs. But creating custom hooks for this use case might get a little tricky.

ā—ļø Caution

These hook don't account for changes to the storage due to other code. This issue can be addressed by listening to the 'storage' event on Window and updating the state accordingly.

useLocalStorage hook

In order to persist a stateful value to localStorage, you can create a custom hook called useLocalStorage. This hook will return a stateful value and a function to update it.

Implementing the hook requires you to use the useState() hook with a function to initialize its value lazily. You can then use a try...catch block and Storage.getItem() to try and get the value from Window.localStorage. If no value is found, use Storage.setItem() to store the defaultValue and use it as the initial state. If an error occurs, use defaultValue as the initial state. Finally, define a function that will update the state variable with the passed value and use Storage.setItem() to store it.

const useLocalStorage = (keyName, defaultValue) => {
  const [storedValue, setStoredValue] = React.useState(() => {
    try {
      const value = window.localStorage.getItem(keyName);

      if (value) {
        return JSON.parse(value);
      } else {
        window.localStorage.setItem(keyName, JSON.stringify(defaultValue));
        return defaultValue;
      }
    } catch (err) {
      return defaultValue;
    }
  });

  const setValue = newValue => {
    try {
      window.localStorage.setItem(keyName, JSON.stringify(newValue));
    } catch (err) {}
    setStoredValue(newValue);
  };

  return [storedValue, setValue];
};

const MyApp = () => {
  const [name, setName] = useLocalStorage('name', 'John');

  return <input value={name} onChange={e => setName(e.target.value)} />;
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <MyApp />
);

useSessionStorage hook

The exact same logic can be applied to persist a stateful value to sessionStorage. You can create a custom hook called useSessionStorage that returns a stateful value and a function to update it. The only difference is that you'll be using Window.sessionStorage instead of Window.localStorage.

const useSessionStorage = (keyName, defaultValue) => {
  const [storedValue, setStoredValue] = React.useState(() => {
    try {
      const value = window.sessionStorage.getItem(keyName);

      if (value) {
        return JSON.parse(value);
      } else {
        window.sessionStorage.setItem(keyName, JSON.stringify(defaultValue));
        return defaultValue;
      }
    } catch (err) {
      return defaultValue;
    }
  });

  const setValue = newValue => {
    try {
      window.sessionStorage.setItem(keyName, JSON.stringify(newValue));
    } catch (err) {}
    setStoredValue(newValue);
  };

  return [storedValue, setValue];
};

const MyApp = () => {
  const [name, setName] = useSessionStorage('name', 'John');

  return <input value={name} onChange={e => setName(e.target.value)} />;
};

ReactDOM.createRoot(document.getElementById('root')).render(
  <MyApp />
);

More like this

Start typing a keyphrase to see matching snippets.