Я хочу, чтобы некоторые части дерева состояния сохранялись в localStorage. Какое место для этого нужно? Редуктор или действие?
Где писать в localStorage в приложении Redux?
Ответ 1
Редуктор никогда не подходит для этого, потому что редукторы должны быть чистыми и не иметь побочных эффектов.
Я бы порекомендовал просто сделать это в подписчике:
store.subscribe(() => {
// persist your state
})
Перед созданием магазина прочитайте эти сохраняемые части:
const persistedState = // ...
const store = createStore(reducer, persistedState)
Если вы используете combineReducers()
, вы заметите, что редукторы, которые получили состояние, будут "загружаться" как обычно, используя значение аргумента по умолчанию state
. Это может быть очень удобно.
Желательно, чтобы вы отклонили своего подписчика, чтобы вы не слишком быстро записывали на localStorage или у вас были проблемы с производительностью.
Наконец, вы можете создать промежуточное программное обеспечение, которое инкапсулирует это как альтернативу, но Id начнет с подписчика, потому что это более простое решение и хорошо выполняет работу.
Ответ 2
Чтобы заполнить пробелы ответа Дэн Абрамова, вы можете использовать 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... */
)
Ответ 3
Одним словом: middleware.
Отъезд redux-persist. Или напишите свой собственный.
[UPDATE 18 Dec 2016] Отредактировано, чтобы удалить упоминание о двух похожих проектах, которые теперь неактивны или устарели.
Ответ 4
Если у кого-то возникли проблемы с вышеупомянутыми решениями, вы можете написать свой собственный. Позвольте мне показать вам, что я сделал. Игнорируйте вещи saga middleware
просто сосредоточьтесь на двух вещах localStorageMiddleware
и методе reHydrateStore
. localStorageMiddleware
вытаскивает все redux state
localStorageMiddleware
и помещает его в 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;
Ответ 5
Я не могу ответить @Gardezi, но вариант, основанный на его коде, может быть:
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 для сохранения только последнего взаимодействия вашего состояния
Ответ 6
Я немного опоздал, но я реализовал постоянное состояние в соответствии с примерами, приведенными здесь. Если вы хотите обновлять состояние только каждые X секунд, этот подход может помочь вам:
Определите функцию-обертку
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!") } }
Вызовите функцию-обертку у вашего подписчика
store.subscribe((state) => { updateLocalStorage(store.getState()) });
В этом примере состояние обновляется не более каждые 5 секунд, независимо от того, как часто запускается обновление.