Redux State Resets On Window Reload (Client Side)

11,627

Solution 1

I think using localStorage is your best option here, since it seems the data you are storing there is needed on the client. If the data is not changing, you shouldn't need to repeatedly query, or watch, the localStorage.

Another thing you can do is wrap a closure around your localStorage, so that you are not always hitting disk when retrieving your "large" data. Every browser implements localStorage differently, so there are no guarantees on consistent behaviour or I/O performance.

This also adds a simple layer of abstraction which hides the implementation, and controls everything related to your user data in one place.

Here is a simple example of user profile data closure:

// UserProfile.js
var UserProfile = (function() {
  var userData = {};

  var getUserData = function() {
    if (!userData) { 
      userData = JSON.parse(localStorage.getItem("userData"));
    }
    return userData;
  };

  var setUserData = function(userData) {
    localStorage.setItem("userData", JSON.stringify(userData));
    userData = JSON.parse(localStorage.getItem("userData"));
  };

  return {
    getUserData: getUserData,
    setUserData: setUserData
  }
})();

export default UserProfile;

Set the user data object: This will overwrite the localStorage, and set the local variable inside the closure.

import UserProfile from '/UserProfile';
UserProfile.setUserData(newUserData);

Get the user data object: This will get the data from the local variable inside the closure, or else go get it from localStorage if it is not set.

import UserProfile from '/UserProfile';
var userData = UserProfile.getUserData();

The idea here is to load data into memory, from localStorage, the first time, when your app loads, or on the first API call. Until such a time when the user profile data changes, (i.e. a user updates their profile, for example), then you would query the API again, and update the data again via the UserProfile.setUserData(..) call.

Solution 2

The question is at what point you need to achieve persistent. I feel that the answer in your case is on a page reload. So if you are worry about performance I'll say: * Update the localStorage only when the state changes. Inside your reducer when you update the state. * Read from localStorage when you boot the app.

(This way you write only when the state changes and you read only once)

P.S. I'll recommend https://github.com/rt2zz/redux-persist package for achieving persistent in Redux apps.

Solution 3

I would only do this as a weak cache and would not rely on it. Local storage is limited (5mb on Chrome e.g.), and may not be available. You'd have to carefully verify that your data was written.

As others have said, you wouldn't be watching localStorage you'd be periodically flushing the store. But I would agree that it seems like a rather coarse hack to blindly assume that all of your state was appropriate to persist in local storage. As with all caching solutions, you need to carefully consider the implications (freshness, expiration, etc.). It sounds like you might want to do this incrementally - pick off a few low-hanging pieces of fruit that are appropriate for caching and consider the implications of caching that state in local storage.

Solution 4

Try redux-persist you can do optimistic persistence, agnostic of the underlying platform (web/mobile).

If you still find performance is a bottleneck. You can do either of the following in steps.

Cache Middleware

Create a middleware that listen's in on changes and records them but only flushes them out every 5 seconds.

Attach an event handler to window.beforeunload to detect user navigating away or closing the browser to flush changes

Persistence Strategy

To persist the data you can use a either of the two strategies below.

  • Store it in localStorage if there is no performance bottle neck.
  • Send a JSON blob to server like file-upload. Fetch last JSON state when app loads and persist locally.

I'd suggest you start of with using redux-persist. If there is still a performance bottle neck then use a cache middleware along with one of the two persistence strategies.

Solution 5

I think that in most cases you want to persist your state in localStorage after certain action(s) happens. At least that's always been the case in the projects where I've needed to persist it.

So, if you are using redux-saga, redux-observable or redux-cycles for orchestrating your side-effects you can easily make that side-effect (persisting the state into localStorage) happen whenever one of those actions take place. I think that's a much better approach than "randomly" persisting the data based on a time-interval.

Share:
11,627
Adeel Imran
Author by

Adeel Imran

I am a full stack developer and designer focusing on making a great UI/UX. I have a passion for working with startups & growing companies by assisting them in creating outstanding product. I live in Lahore, Pakistan, with my 2 dogs. In the past few years, I have had the experience of working with numerous clients from all over the world. I enjoy taking complicated problems & turning them into simple, elegant solutions. I love writing beautiful code that is written structurally & indented properly. When I am not doing my ninja skills with code or fighting crime, you'll probably find me in the gym or at a coffee shop sipping on some good cappuccino.

Updated on June 05, 2022

Comments

  • Adeel Imran
    Adeel Imran almost 2 years

    I have very large and complicated objects like userInfo, chatInfo, and etc as in objects & arrays with very large and nested information. The thing is in my react app every time I refresh my page the redux state gets reset and I have to call all those API's again.

    I did some research on this topic. I checked Dan Abramov's egghead tutorial on redux. What he does is maintain the redux state in localStorage of the browser and updated the localStorage after every 100 or 500 ms. I feel as if this is a code smell.

    Continuously watching the localStorage state and updating it, wouldn't it effect the performance of the browser. I mean wasn't this on of the reasons Angular 1 failed because it continuously kept on watching state variables and after a while if the site was kept live in the browser it just slowed down. Because our script continuously kept on checking the state of the variables. i feel as if we are doing the same thing here.

    If maintaining the redux state in localStorage is the right approach can someone tell me why so? And if not is there a better approach?


    This is not a duplicate of How can I persist redux state tree on refresh? because I am asking for advice whether persisting state in local storage is a code smell or not

  • Zevgon
    Zevgon over 6 years
    I agree, redux-persist is the answer in my opinion
  • Michael Freidgeim
    Michael Freidgeim over 4 years
    The new location of redux-storage is github.com/react-stack/redux-storage