Persist your React State in the Browser
Tags: react, persist, indexeddb, usedbstate
Published: 2024-06-11 18:15:41

### The Problem

Have you ever wanted to persist your React state in the browser? Have you ever created a long form and wished its data wouldn't vanish when you refresh the page before you submit it?

well, I have too.

### Brainstorming solutions

I've been thinking about this for a while. 
Basically, you have to store the form data in the browser. There are a few ways to do this. There is localStorage, sessionStorage, and cookies. These work great for small amounts of data and simple forms. I wanted to build something that is robust, can handle variety of data, and as simple as using useState hook in React.

That's when I came across IndexedDB. 

Did you know the browser has its own database? I mean not `key:value` pairs like localStorage, but an actual database that you can store and query data from!! 

<!-- ** add a gif of blowing mind ** -->
![Mind Blown](https://media1.tenor.com/m/1ve5YKbOtOgAAAAC/mind-blown-boom.gif)

### IndexedDB

<!-- link IndexedDB API from MDN docs -->

This is what the official MDN doc says about IndexedDB:

> [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API)  is a low-level API for client-side storage of significant amounts of structured data, including files/blobs. This API uses indexes to enable high-performance searches of this data. While Web Storage is useful for storing smaller amounts of data, it is less useful for storing larger amounts of structured data. IndexedDB provides a solution. 

In simple terms, you can store large amounts of complex data and also query it quickly and efficiently just like you would with a database. Web storage would store small amounts (~10MB) of data in the form of strings upon which you cannot query.

And guess what? You can even store files and blobs in IndexedDB!

<!-- WOW GIF -->
![wow gif](https://media1.tenor.com/m/QiIRP06rosgAAAAd/wow-oh-my.gif)

### The Solution

If you look at the [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) documentation, you will see that it is fairly complex to setup and use. I wanted something that is as simple as using useState hook. Infact I want it to have same syntax and same ease of use as useState hook.

So I started building a simple library that will help you store and query your data in IndexedDB just as easily as you would with useState.

That's how  [`use-db-state`](https://www.npmjs.com/package/use-db-state) was born.

### Introducing use-db-state
`use-db-state` is a custom React hook that allows you to persist state in the browser using IndexedDB. It handles all the complexity of IndexedDB, giving you a simple and familiar interface to work with.

Let's see how you can use it.

#### Installation
First, you need to install the library via npm:

```
npm install use-db-state
```
#### Usage
Here's a simple example to get you started:

*please go through the [documentation](https://www.npmjs.com/package/use-db-state) for detailed explaination of the parameters*

```
import React from 'react';
import { useDbState } from 'use-db-state';

const SimpleForm = () => {
  const [value, setValue] = useDbState('formInput', '');

  return (
    <div>
      <h1>Persisted Form</h1>
      <input 
        type="text" 
        value={value} 
        onChange={(e) => setValue(e.target.value)} 
        placeholder="Type something..." 
      />
      <p>Persisted Value: {value}</p>
    </div>
  );
};

export default SimpleForm;
```
And just like that your state will persist even if you refresh the page! 
Your state is now stored in IndexedDB. If you want to see where your data is stored, open your browser's developer console, go to Applications tab, and on the left panel look for IndexedDB! Click on it and you should see your data inside.

#### Going Deeper
But wait, there's more! `use-db-state` also comes with a handy hook called `useDbKeyRemover`. This hook allows you to remove specific keys from IndexedDB.

#### Why is useDbKeyRemover Important?
When dealing with persisted state, there are situations where you may need to clean up or remove specific entries from your IndexedDB store. For instance:

- **Form Resets**: After submitting a form, you might want to clear the saved input values to avoid stale data when the user revisits the form.
- **User Logout**: On user logout, you might want to clear user-specific data from IndexedDB to ensure privacy and data security.
- **Data Updates**: Sometimes, you need to remove outdated data to make way for new, updated data.
By using `useDbKeyRemover`, you can easily remove specific keys without having to deal with the low-level complexities of IndexedDB.

Here's a more complex example demonstrating both `useDbState` and `useDbKeyRemover`:
*please go through the [documentation](https://www.npmjs.com/package/use-db-state) for detailed explaination of the parameters*

#### Example: Form with Key Removal
```
import React from 'react';
import { useDbState, useDbKeyRemover } from 'use-db-state';

const FormWithKeyRemoval = () => {
  const [name, setName] = useDbState('name', '');
  const [email, setEmail] = useDbState('email', '');
  const removeKey = useDbKeyRemover();

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form submitted:', { name, email });
    setName('');
    setEmail('');
    removeKey('name');
    removeKey('email');
  };

  return (
    <div>
      <h1>Form with Key Removal</h1>
      <form onSubmit={handleSubmit}>
        <div>
          <label>
            Name:
            <input 
              type="text" 
              value={name} 
              onChange={(e) => setName(e.target.value)} 
            />
          </label>
        </div>
        <div>
          <label>
            Email:
            <input 
              type="email" 
              value={email} 
              onChange={(e) => setEmail(e.target.value)} 
            />
          </label>
        </div>
        <button type="submit">Submit</button>
      </form>
    </div>
  );
};

export default FormWithKeyRemoval;
```
#### When to Use use-db-state
`use-db-state` is perfect for scenarios where you need to persist state across page reloads or browser sessions. Some common use cases include:

- **Forms**: Prevent users from losing their input data in case they accidentally refresh the page.
- **User Preferences**: Persist theme, language, or other user settings.
- **Shopping Carts**: Maintain cart contents between sessions.
- **Complex Forms**: Save progress in multi-step forms.
- And much more!!

### Conclusion
Persisting state in the browser doesn't have to be complex. With `use-db-state`, you can leverage the power of IndexedDB with the simplicity of `useState`. This library abstracts away the complexities, allowing you to focus on building great user experiences.

Give `use-db-state` a try in your next project and make state persistence a breeze!

<!-- GIF of high-five -->
![hifi](https://media1.tenor.com/m/bCy65kY5WHIAAAAC/la-biscornue-biscornue.gif)

Happy coding!

-----------------

Feel free to reach out if you have any questions or need further assistance. You can find the full documentation on my [GitHub repository](https://github.com/ajejey/use-db-state-hook).

If you found this article helpful, share it with your fellow developers and spread the word about `use-db-state`!

You can follow me on [github](https://github.com/ajejey) and [Linkedin](https://www.linkedin.com/in/ajey-nagarkatti-28273856/)