Где писать в localStorage в приложении Redux?

Я хочу сохранить некоторые части моего дерева состояний в localStorage. Какое место для этого подходит? Редуктор или действие?

5 ответов


редуктор никогда не является подходящим местом для этого, потому что редукторы должны быть чистыми и не иметь побочных эффектов.

Я бы рекомендовал просто сделать это в подписчике:

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

перед созданием магазина прочитайте эти сохраненные части:

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

если вы используете combineReducers() вы заметите, что редукторы, которые не получили состояние, будут "загружаться" как обычно, используя их по умолчанию state значение аргумента. Это может быть очень удобно.

это желательно, чтобы вы дебютировали своего подписчика, чтобы вы не писали в localStorage слишком быстро, или у вас будут проблемы с производительностью.

наконец, вы можете создать промежуточное ПО, которое инкапсулирует это в качестве альтернативы, но я бы начал с подписчика, потому что это более простое решение и хорошо выполняет эту работу.


чтобы заполнить пробелы в ответе Дана Абрамова, вы можете использовать store.subscribe() такой:

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

перед созданием магазина, чек localStorage и проанализируйте любой JSON под вашим ключом следующим образом:

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

вы тогда передайте это peristedState константа к вашему createStore способ такой:

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

одним словом: промежуточное ПО.

проверить redux-persist. Или написать свою собственную.

[UPDATE 18 Dec 2016] отредактировано, чтобы удалить упоминание о двух подобных проектах, которые теперь неактивны или устарели.


если у кого-то есть какие-либо проблемы с вышеуказанными решениями, вы можете написать свой собственный. Позвольте мне показать вам, что я сделал. Игнорировать saga middleware все просто сосредоточиться на двух вещах localStorageMiddleware и reHydrateStore метод. the localStorageMiddleware вытащить все redux state и кладет его в local storage и rehydrateStore вытащить все applicationState в локальном хранилище, если он присутствует и помещает его в 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;

Я не могу ответить @Гардези, но на основе его кода может быть:

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
    )
);

разница в том, что мы просто сохраняем некоторые действия, вы можете использовать функцию debounce для сохранения только последнего взаимодействия вашего состояния