Storing User Preferences in React
Tags: react, javascript, beginners, tutorial
Published: 2022-01-08 04:18:42

> This tutorial was originally posted [here](https://tobyhagan.com/blog/storing-user-preferences-in-react)

## Allowing users to select preferences is great, if they stick around...

The preferences, that is. User retention is an entirely different conversation. But as far as persisting a user's data goes, the approach is surprisingly straight forward. 

###  Be Safe
When storing a user's data, it is important to keep security in mind. Don't save things like a user's password or a secret key where unwanted intrusions may occur. For the purposes of this demonstration, we will only be storing the user's theme preference. 

### Getting Started

In the [last tutorial](https://tobyhagan.com/blog/dark-mode-using-react) we learned how to create a dark mode toggle button:

`src/App.js`

```js
import './App.css';
import { useEffect, useState } from 'react';

function App() {
  const [darkMode, setDarkMode] = useState(false);

  useEffect(() => {
    if (darkMode) {
      document.body.classList.add('dark');
    }
    else {
      document.body.classList.remove('dark');
    }
  }, [darkMode]);

  return (
    <div className="App">
      <h1>{darkMode ? 'Dark Mode' : 'Light Mode'}</h1>
      <p>This is a test</p>
      <button
        className="dark-mode-toggle"
        onClick={() => {
          setDarkMode(!darkMode);
        }}>
        <div className="dark-mode-slider" />
      </button>
    </div>
  );
}

export default App;

```
`src/App.css`
```css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
.App {
  height: 100vh;
  width: auto;
  text-align: center;
  font-size: 5em;
  color: #2e3440;
  background-color: #d8dee9;
  transition: all 0.2s ease;
}
.dark,
.dark .App {
  color: #d8dee9;
  background-color: #2e3440;
  transition: all 0.2s ease;
}

/* Button Styles */

.dark-mode-toggle {
  width: 80px;
  height: 36px;
  border-radius: 50px;
  top: 0;
  left: 0;
}
.dark-mode-toggle svg {
  fill: #000;
}
.dark-mode-slider {
  height: 30px;
  width: 30px;
  border-radius: 50%;
  background-color: #2e3440;
  display: flex;
  position: relative;
  transform: translateX(0px);
  transition: all 0.2s ease;
}

.dark .dark-mode-slider {
  transform: translateX(45px);
}

```

### Where did it go?

Lets take a closer look at our functionality. When we click the button, our styling toggles between light and dark mode, awesome! If you switch to dark mode and refresh, you may notice you're right back to light mode, as that is our default setting. 

### Making it stick

Lets fix this behavior by storing our preference using the [localStorage api](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API)

We'll need to update our `useEffect` hook from it's current state:

```js

  useEffect(() => {
    if (darkMode) {
      document.body.classList.add('dark');
    }
    else {
      document.body.classList.remove('dark');
    }
  }, [darkMode]);

```

to the following: 
```jsx
 
useEffect(() => {
    if (darkMode) {
      localStorage.setItem('prefersDarkMode', 'true');
      document.body.classList.add('dark');
    }
    else {
      localStorage.setItem('prefersDarkMode', 'false');
      document.body.classList.remove('dark');
    }
  }, [darkMode]);

```

In this change, we've told our application to store a key value pair to our browser, but you may have noticed we are only setting the item and not using it to control our state. To accomplish this, we need to add another `useEffect` hook above the one we just edited, it should look like this:

```js

  useEffect(() => {
    const storedPreference = localStorage.getItem('darkModePreference');
    if (storedPreference) {
      setDarkMode(JSON.parse(storedPreference));
    }
  }, []);

```

Lets take a closer look. We are using the `getItem` method to retrieve the value of the key we set earlier, and using the `JSON.parse` method to convert the string value to a [boolean](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean).
We're leaving the dependency array empty, because we only want this to run on the initial mount of our application. With this change complete, we are now able to refresh our page, and our theme preference is loaded without us having to toggle the button.  

### Saving some time

In some cases, users will already have certain preferences available from their device, and we can use those to set our initial state. In this case, we can use the [matchMedia api](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) to check if the user has a  theme preference set in their device.To accomplish this, we can edit the previous `useEffect` hook to look like this:

```js

    useEffect(() => {
        const storedPreference = localStorage.getItem('darkModePreference');
        if (storedPreference) {
        setDarkMode(JSON.parse(storedPreference));
        }
        else {
        const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
        setDarkMode(prefersDarkMode);
        }
    }, []);

```

We're using an `if` statement to check if the user has a preference set in their device. If they do, we'll set the state to the value of the preference. If not, we'll use the `matchMedia` api to check if the user prefers dark mode. If they do, we'll set the state to using the `prefers-color-scheme: dark` media query. This will return a boolean value, and we'll set `prefersDarkMode` to that value. This will trigger our initial `useEffect` hook to run, and update our application to match the user's preference. 

This is all it takes to persist data in the browser. This was just a small example, but many developers find this useful for storing a multitude of non-sensitive data, without having to make expensive calls to the server among many other creative uses.