Asher Cohen
Back to posts

Redux - Resetting State with a Root Reducer

Bonus: how to reset state selectively

I am using Redux for state management like many of you, but have you ever tried to reset the store to its initial state?

For example, let’s say I have two user accounts (u1 and u2). Imagine the following sequence of events:

  1. User u1 logs into the app and does something, so we cache some data in the store.
  2. User u1 logs out.
  3. User u2 logs into the app without refreshing.

At this point, the cached data that is associated with u1 could leak and I would like to clean it up.

How can I reset the Redux store to its initial state when the first user logs out?

The situation described above can highly affect your application security especially when you have a caching mechanism to avoid HTTP calls.

The following solution is valid for both React and React-Native so it can be used in the browser as well as mobile applications.

For the best of you that get to the end of this article I’ve also added a bonus trick.

Disclaimer

I assume that you have your reducers and actions already setup and like me use combineReducers in a store/index.js folder to… well combine them together.

Also the concept of a reducer’s initialState (or preloadedState) should be clear to you, if not I have left a link to Redux documentation further below.
I encourage you to read this Redux tutorial before continuing.


The solution

I will give you the solution now and then explain the reasons in depth; this way you can digest it while reading.

gist.github.com/asherccohen/72d918daafcb0de8deb39f95a77d9202

Wait, did I just reassign undefined to state? YES, I DID. Why?

Because reducers are supposed to return the initial state when they are called with undefined as the first argument, no matter the action.

The why

Let’s take our OrderReducer as an example.

It will be something like this, a switch that captures actions and an INITIAL_STATE object with default parameters:

gist.github.com/asherccohen/5ac219316dd67a963a98ba8b28e1b9ef

And our store is created with a snippet like this:

gist.github.com/asherccohen/676af597264403a1f2f66b5bfa6d692f

If we log the state at this point it will contain all default parameters set by INITIAL_STATE.
Why? Because the second argument passed to createStore was undefined.
This is the state passed to your reducer the first time.

When Redux initializes it dispatches a “dummy” action to fill the state.
So your order reducer is called with state equal to undefined.
This is exactly the case that activates the default argument.

“Simplicity is about subtracting the obvious and adding the meaningful.”
— John Maeda, The Laws of Simplicity

A clear explanation of how combineReducers and preloadedState work can be found in the Redux docs:
https://redux.js.org/recipes/structuring-reducers/initializing-state

There is also a library that uses this concept if you want a quick and easy solution:
https://github.com/wwayne/redux-reset

For clarity, this is not a specific Redux behavior, it works exactly the same with plain JavaScript.
You don’t trust me? Try this JSFiddle and check the results:
https://jsfiddle.net/bjs6uda1/2/

Mutation

Ok, ok, not these mutants…

If you paid attention to the process you might be worried about how we reassigned a value to state.
Note that I’m not mutating the state here, I am reassigning the reference of a local variable called state before passing it to another function.
Mutating a state object would be a violation of Redux principles.


Disclaimer (redux-persist)

If you use redux-persist, you may also need to clean your storage.
Redux-persist keeps a copy of your state in a storage engine, and the state copy will be loaded on refresh.

You need to import the appropriate storage engine, then parse the state before setting it to undefined and clean each storage state key.

gist.github.com/asherccohen/ff8b548926811cfe62c9268c69299775


A special thanks goes to all the people who answered this question on StackOverflow and gave a clear explanation:
https://stackoverflow.com/questions/35622588/how-to-reset-the-state-of-a-redux-store

BONUS — Reset selective Redux keys (aka choose what to reset on logout)

This solution wouldn’t be complete if you couldn’t selectively reset the store.
Here’s an easy way: using destructuring we maintain a reference to the properties of the Redux store that we want to keep.
We can then pass them to the state upon reassignment.

gist.github.com/asherccohen/f4c05f6317c74f9e863648c248ebf052

The properties that you define will be safely kept as is while all other keys will receive undefined and therefore return to initial state.

Bear in mind that this approach can also be used with different actions to create powerful combinations.

gist.github.com/asherccohen/8f61589f41978953bd877c48d1195f7f

So now go ahead, reset your store and let me know if this saved leaking data to different users…or leave your comments and we’ll discuss.