Where to write to localStorage in a Redux app?

一曲冷凌霜 提交于 2019-11-26 01:06:03

问题


I want to persist some parts of my state tree to the localStorage. What is the appropriate place to do so? Reducer or action?


回答1:


Reducer is never an appropriate place to do this because reducers should be pure and have no side effects.

I would recommend just doing it in a subscriber:

store.subscribe(() => {
  // persist your state
})

Before creating the store, read those persisted parts:

const persistedState = // ...
const store = createStore(reducer, persistedState)

If you use combineReducers() you’ll notice that reducers that haven’t received the state will “boot up” as normal using their default state argument value. This can be pretty handy.

It is advisable that you debounce your subscriber so you don’t write to localStorage too fast, or you’ll have performance problems.

Finally, you can create a middleware that encapsulates that as an alternative, but I’d start with a subscriber because it’s a simpler solution and does the job well.




回答2:


To fill in the blanks of Dan Abramov's answer you could use store.subscribe() like this:

store.subscribe(()=>{
  localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})

Before creating the store, check localStorage and parse any JSON under your key like this:

const persistedState = localStorage.getItem('reduxState') ? JSON.parse(localStorage.getItem('reduxState')) : {}

You then pass this peristedState constant to your createStore method like this:

const store = createStore(
  reducer, 
  persistedState,
  /* any middleware... */
)



回答3:


In a word: middleware.

Check out redux-persist. Or write your own.

[UPDATE 18 Dec 2016] Edited to remove mention of two similar projects now inactive or deprecated.




回答4:


If anybody is having any problem with the above solutions, you can write your own to. Let me show you what I did. Ignore saga middleware things just focus on two things localStorageMiddleware and reHydrateStore method. the localStorageMiddleware pull all the redux state and puts it in local storage and rehydrateStore pull all the applicationState in local storage if present and puts it in redux store

import {createStore, applyMiddleware} from 'redux'
import createSagaMiddleware from 'redux-saga';
import decoristReducers from '../reducers/decorist_reducer'

import sagas from '../sagas/sagas';

const sagaMiddleware = createSagaMiddleware();

/**
 * Add all the state in local storage
 * @param getState
 * @returns {function(*): function(*=)}
 */
const localStorageMiddleware = ({getState}) => { // <--- FOCUS HERE
    return (next) => (action) => {
        const result = next(action);
        localStorage.setItem('applicationState', JSON.stringify(
            getState()
        ));
        return result;
    };
};


const reHydrateStore = () => { // <-- FOCUS HERE

    if (localStorage.getItem('applicationState') !== null) {
        return JSON.parse(localStorage.getItem('applicationState')) // re-hydrate the store

    }
}


const store = createStore(
    decoristReducers,
    reHydrateStore(),// <-- FOCUS HERE
    applyMiddleware(
        sagaMiddleware,
        localStorageMiddleware,// <-- FOCUS HERE 
    )
)

sagaMiddleware.run(sagas);

export default store;



回答5:


I cannot answer @Gardezi but an option based on his code could be:

const rootReducer = combineReducers({
    users: authReducer,
});

const localStorageMiddleware = ({ getState }) => {
    return next => action => {
        const result = next(action);
        if ([ ACTIONS.LOGIN ].includes(result.type)) {
            localStorage.setItem(appConstants.APP_STATE, JSON.stringify(getState()))
        }
        return result;
    };
};

const reHydrateStore = () => {
    const data = localStorage.getItem(appConstants.APP_STATE);
    if (data) {
        return JSON.parse(data);
    }
    return undefined;
};

return createStore(
    rootReducer,
    reHydrateStore(),
    applyMiddleware(
        thunk,
        localStorageMiddleware
    )
);

the difference is that we are just saving some actions, you could event use a debounce function to save only the last interaction of your state




回答6:


I'm a bit late but I implemented a persistent state according to the examples stated here. If you want to update the state only every X seconds, this approach may help you:

  1. Define a wrapper function

    let oldTimeStamp = (Date.now()).valueOf()
    const millisecondsBetween = 5000 // Each X milliseconds
    function updateLocalStorage(newState)
    {
        if(((Date.now()).valueOf() - oldTimeStamp) > millisecondsBetween)
        {
            saveStateToLocalStorage(newState)
            oldTimeStamp = (Date.now()).valueOf()
            console.log("Updated!")
        }
    }
    
  2. Call a wrapper function in your subscriber

        store.subscribe((state) =>
        {
        updateLocalStorage(store.getState())
         });
    

In this example, the state is updated at most each 5 seconds, regardless how often an update is triggered.



来源:https://stackoverflow.com/questions/35305661/where-to-write-to-localstorage-in-a-redux-app

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!