Using Local Storage in React with Your Own Custom useLocalStorage Hook
Tags: react, javascript, webdev, programming
Published: 2020-09-02 11:45:13

---
title: Using Local Storage in React with Your Own Custom useLocalStorage Hook
published: true
description: One tool for storing data browser-side we might reach for is local storage. In this post, we’ll use local storage in React by rolling our own useLocalStorage hook.
tags: react, javascript, webdev, programming
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/tq84twpdigaugfm6ytyb.jpg
canonical_url: https://typeofnan.dev/using-local-storage-in-react-with-your-own-custom-uselocalstorage-hook/
---

One tool for storing data browser-side we might reach for is local storage. In this post, we'll use local storage in React by rolling our own useLocalStorage hook.

<hr />

## If you enjoy this tutorial, please give it a 💓, 🦄, or 🔖 and consider:

- signing up for [my free weekly dev newsletter](https://buttondown.email/devtuts)
- subscribing to [my free YouTube dev channel](https://www.youtube.com/c/devtutsco?sub_confirmation=1)

<hr />

# Our Approach

To approach this problem, let's break it down into pieces.

1. **Provide a local storage key.** Local storage works off of key-value pairs, so we'll want to be able to provide a `key` for our stored data.
2. **Provide a default value.** If there's no existing data in local storage under the provided `key`, we'll want to be able to provide a `defualtValue` for our data.
3. **Load the local storage value into state (or default if no local storage value exists).** We'll still be maintaining stateful information in our app, so we can still use the `useState` hook. The difference here is we'll use the local storage value if it exists before we consider the user-provided `defaultValue`.
4. **Save the stateful data to local storage.** When our stateful data changes, we'll want to make sure local storage is kept up to date. Therefore, on any change to our variable, let's run an effect to sync up local storage.
5. **Expose the state variable and a setter.** Much like the `useState` hook, our `useLocalStorage` hook will return a 2-element array. The first element will be the variable and the second will be a setter for that variable.

# Creating the Hook

Let's create the hook! As noted above, the hook will take two inputs: the `key` that will be used in `localStorage` and the `defaultValue`, which will be used in the even that there's nothing in `localStorage` yet.

**useLocalStorage.js**

```javascript
export const useLocalStorage = (key, defaultValue) => {};
```

Next up, let's load any data in `localStorage` under the provided `key`.

```javascript
export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
};
```

Now we know that the initial value for our stateful variable is going to be this `stored` value. _However_, if there's nothing in `localStorage` yet under the provided `key`, we'll default to the user-provided `defaultValue`.

Note: since `localStorage` data are stored as strings, we make sure to `JSON.parse` any data we retrieve from there.

```javascript
export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
  const initial = stored ? JSON.parse(stored) : defaultValue;
};
```

Now that we have our `initial` value for state, we can use our regular `useState` hook format and return our stateful variable and its setter.

```javascript
import { useState } from 'react';

export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
  const initial = stored ? JSON.parse(stored) : defaultValue;
  const [value, setValue] = useState(initial);
  return [value, setValue];
};
```

Almost done! We still have one outstanding requirement we haven't met yet: we need to save any data back to `localStorage` when it's changed. I like doing this in a `useEffect` hook that's triggered when `value` changes.

```javascript
import { useState, useEffect } from 'react';

export const useLocalStorage = (key, defaultValue) => {
  const stored = localStorage.getItem(key);
  const initial = stored ? JSON.parse(stored) : defaultValue;
  const [value, setValue] = useState(initial);

  useEffect(() => {
    localStorage.setItem(key, JSON.stringify(value));
  }, [key, value]);

  return [value, setValue];
};
```

There we have it! Whenever `value` changes, our effect will run, meaning we'll set the `localStorage` item to be set to the `JSON.stringify` of our `value`. Note that the provided `key` is _also_ a dependency of our effect, so we include it in the dependency array for completeness even though we don't really expect it to change.

# Testing Out Our New Hook

Let's take the hook our for a test drive! We'll create a simple component that has a text input whose value is based on our `useLocalStorage` hook.

**App.jsx**

```jsx
import React from 'react';
import { useLocalStorage } from './useLocalStorage';

function App() {
  const [name, setName] = useLocalStorage('username', 'John');
  return (
    <input
      value={name}
      onChange={e => {
        setName(e.target.value);
      }}
    />
  );
}

export default App;
```

Now let's run our app. We can see that, when we first run the app, our stateful `name` variable is defaulted to the string `John`. However, when we change the value and then refresh the page, we're now defaulting to the value persisted to `localStorage`.

![useLocalStorage in use](https://dev-to-uploads.s3.amazonaws.com/i/zcpt06nlzia30ayunwys.gif)

Success!