How can I persist redux state tree on refresh?

2019-01-13 01:11发布

问题:

The first principal of Redux documentation is:

The state of your whole application is stored in an object tree within a single store.

And I actually thought that I understand all of principals well. But I'm now confused what does application means.

If application means just one of little complicated part in website and works in just one page, I understand. But what if application means whole website? Should I use LocalStorage or cookie or something for keep the state tree? but what if browser doesn't support LocalStorage?

I want to know how developers keep their state tree! :)

回答1:

If you would like to persist your redux state across a browser refresh, it's best to do this using redux middleware. Check out the redux-persist and redux-storage middleware. They both try to accomplish the same task of storing your redux state so that it may be saved and loaded at will.



回答2:

While the provided answer was valid at some point it is important to notice that the redux-storage package has been deprecated and it's no longer being maintained...

The original author of the package redux-storage has decided to deprecate the project and no longer maintained.

Now, if you don't want to have dependencies on other packages to avoid problems like these in the future it is very easy to roll your own solution.

All you need to do is:

1- Create a function that returns the state from localStorage and then pass the state to the createStore's redux function in the second parameter in order to hydrate the store

 const store = createStore(appReducers, state);

2- Listen for state changes and everytime the state changes, save the state to localStorage

store.subscribe(() => {
    //this is just a function that saves state to localStorage
    saveState(store.getState());
}); 

And that's it...I actually use something similar in production, but instead of using functions, I wrote a very simple class as below...

class StateLoader {

    loadState() {
        try {
            let serializedState = localStorage.getItem("http://contoso.com:state");

            if (serializedState === null) {
                return this.initializeState();
            }

            return JSON.parse(serializedState);
        }
        catch (err) {
            return this.initializeState();
        }
    }

    saveState(state) {
        try {
            let serializedState = JSON.stringify(state);
            localStorage.setItem("http://contoso.com:state", serializedState);

        }
        catch (err) {
        }
    }

    initializeState() {
        return {
              //state object
            }
        };
    }
}

and then when bootstrapping your app...

import StateLoader from "./state.loader"

const stateLoader = new StateLoader();

let store = createStore(appReducers, stateLoader.loadState());

store.subscribe(() => {
    stateLoader.saveState(store.getState());
});

Hope it helps somebody

Performance Note

If state changes are very frequent in your application, saving to local storage too often might hurt your application's performance, especially if the state object graph to serialize/deserialize is large. For these cases, you might want to debounce or throttle the function that saves state to localStorage using RxJs, lodash or something similar.



回答3:

The original question is

I want to know how developers keep their state tree! :)

Well since i dont see this answer and you did use the React label; often React webapps are implemented as a SPA (Single Page Application) that does not really refresh the browser. They might make it appear as if it did by changing the URL you see in the address bar though. A popular way to do this is react-router.

But still a SPA state does not survive a browser refresh, so that is when redux-persist comes in.