Persistent Data with React-hooks and Context API

I’d like to showcase a very simple solution to persisting data between sessions in a web app — something many developers will have to manage.

You may want to persist data between sessions to allow a browser to remember a logged-in user, have granular control over cached data, or a plethora of other cases.

In this article, I’ll show my solution to persisting data and why I choose to do it this way.

Ideally, making data persistent between sessions should require very little cognitive overheard; it should be simple, smart, and efficient to use. Previous to adopting React hooks, my solution involved a lot of boilerplate on top of the Context API, and although it was smart, it wasn’t very efficient and it wasn’t as simple as I would have hoped for. However, the flexibility for hooks to modularize logic is fantastic and it enables us to easily build and extend the logic we need.

I use the React Context API as my application’s data-store, and in many cases, if I’m accessing data globally, I may want that data to persist across sessions. The easiest example is storing a logged-in user’s credentials such as their email and token. So I needed my solution to integrate nicely with Context, but it would also be nice if it worked in one-off cases, such as tracking if a browser has already visited a page.

After some research and experimentation, it turns out there is a very simple solution! For starters, we need to think about actually storing and retrieving the data. I opted to take advantage of an incredibly useful package called Store. This package automatically picks the best storage solution for the browser it’s working with, and has intelligent fall-backs if something fails. Check out the documentation if you haven’t used it yet.

Next, I just needed to create a new hook with the functionality I needed. I decided that I wanted to combine state management with keeping the persisted data in-sync automatically. This entailed two steps: retrieving the data from the store when we initially load the hook, and saving data to the store any time the state changes.

Thus I created the new hook usePersistState:

With that, we’re ready to use the new hook to persist data wherever we need! As I mentioned, in a majority of my cases, I care about persisting data from within Conext, and the new hook makes sure I can do that seemlessly.

That’s it! you can use this hook exactly like you would useState with the only addition being you now need to add a storageKey when you initiate it.

As an extra note, you may notice that the hook isn’t watching for changes in the store after the initial load, its only making changes one-way. This is on purpose. Each instance of storageKey should be singular. If you need to access those values from more than one place, you should probably integrate it within a Context or some other global storage such as Redux. Besides, it’d be significantly less efficient and could cause race-condition bugs if you try having more than one instance retrieving/saving the same persistent data.