Persistent State in React
Tags: react, javascript
Published: 2020-06-11 06:10:54

> **This was originally posted on my [blog](https://akhilaariyachandra.com/persistent-state-in-react/ "Persistent State in React") on May 26th, 2020. Check it out for my posts on React and JavaScript.**

Sometimes we need to preserve the state in a React app in cases where we close the browser or reload the page. In this guide I'll show you a simple custom hook to store the state in `localstorage`.

> This guide will not work as is in frameworks like [Next.js](https://nextjs.org/) or [Gatsby](http://gatsbyjs.org/) because the components aren't first rendered in the browser and `localstorage` can't be accessed. If you want to learn more about how rendering differs in the browser and the server check out this [awesome post](https://joshwcomeau.com/react/the-perils-of-rehydration/ "The Perils of Rehydration").

First create a function called `useStickyState` with the initial state (`initialState`) as an argument.

```jsx
import React from "react";

const useStickyState = (initialState = null) => {};
```

Then let's initialize the state and return it and the function to change it.

```jsx
import React from "react";

const useStickyState = (initialState = null) => {
  const [state, useState] = React.useState(initialState);

  return [state, setState];
};
```

Next we'll add an effect to store the state in `localstorage` when the state changes. Since we need an key to store a value in local storage we'll add one as an argument.

```jsx
import React from "react";

const useStickyState = (key = "sticky", initialState = null) => {
  const [state, useState] = React.useState(initialState);

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

  return [state, setState];
};
```

In its current form the state will always initialize with `initialState`, but we need to load the state from `localstorage` if available. We can use [lazy initialization](https://reactjs.org/docs/hooks-reference.html#lazy-initial-state "Lazy initial state") to check `localstorage` and use it's value if present. If not, use `initialState` instead.

```jsx
import React from "react";

const useStickyState = (key = "sticky", initialState = null) => {
  const [state, setState] = React.useState(() => {
    const storedState = localStorage.getItem(key);

    return storedState ?? initialState;
  });

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

  return [state, setState];
};
```

To finish up the hook, let's add and return a function to remove clear up the value in `localstorage`.

```jsx
import React from "react";

const useStickyState = (key = "sticky", initialState = null) => {
  const [state, setState] = React.useState(() => {
    const storedState = localStorage.getItem(key);

    return storedState ?? initialState;
  });

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

  const clearState = () => localStorage.removeItem(key);

  return [state, setState, clearState];
};
```

# Wrapping up

Below is an example on how to use the `useStickyState` hook to save the value in an `<input>`

```jsx
import React from "react";

const useStickyState = (key = "sticky", initialState = null) => {
  const [state, setState] = React.useState(() => {
    const storedState = localStorage.getItem(key);

    return storedState ?? initialState;
  });

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

  const clearState = () => localStorage.removeItem(key);

  return [state, setState, clearState];
};

export default function App() {
  const [value, setValue, clearValue] = useStickyState(
    "sticky",
    "Hello World!!!"
  );

  return (
    <div className="App">
      <h1>{`Value : ${value}`}</h1>

      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />

      <button onClick={() => clearValue()}>Clear</button>
    </div>
  );
}
```

You can check out a working example [here](https://codesandbox.io/s/persistent-react-state-6s73k?fontsize=14&hidenavigation=1&theme=dark).

{% codesandbox persistent-react-state-6s73k %}