const useStickyState = (defaultValue, key) => {
  const [value, setValue] = React.useState(() => {
    const stickyValue = window.localStorage.getItem(key);
    return stickyValue !== null
      ? JSON.parse(stickyValue)
      : defaultValue;
  React.useEffect(() => {
    window.localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);
  return [value, setValue];


The useState React hook is great for state that should be freshly initialized on every visit, but what about for state that should be persisted between sessions?

A good example of this is filters. If I set a filter to sort based on price instead of newest items, that value should "stick", so that if I come back to this site in a week, it remembers that I want to sort by price.

The useStickyState hook works just like useState, except it backs up to (and restores from) localStorage.



How to use it

It's used just like React.useState, except it takes two arguments: a default value, and a key:

const SomeComponent() { 
  const [color, setColor] = useStickyState('blue', 'persisted-color');

The second argument, key, will be used as the localStorage key. It's important that each useStickyState instance uses a unique value.


This hook is not SSR safe, if you use SSR, or a framework that makes use of it (eg. Gatsby, Next.js), you'll get an error with this hook as-is.

This is not an easy problem to solve; when the app is rendered on the server, we don't have access to the user's localStorage.

The easiest solution would be to only use this hook in client-side components.