Je souhaite conserver certaines parties de mon arbre d'état dans le stockage local. Quel est le lieu approprié pour le faire? Réducteur ou action?
Réducteur n'est jamais un endroit approprié pour cela car les réducteurs doivent être purs et ne pas avoir d'effets secondaires.
Je recommanderais simplement de le faire chez un abonné:
store.subscribe(() => {
// persist your state
})
Avant de créer le magasin, lisez les parties persistantes:
const persistedState = // ...
const store = createStore(reducer, persistedState)
Si vous utilisez combineReducers()
, vous remarquerez que les réducteurs qui n'ont pas reçu l'état "démarreront" normalement à l'aide de la valeur par défaut de leur argument state
. Cela peut être très pratique.
Il est conseillé d’attaquer votre abonné afin de ne pas écrire trop vite sur localStorage, sinon vous aurez des problèmes de performances.
Enfin, vous pouvez créer un middleware qui l’encapsule à la place, mais je commencerais par un abonné car c’est une solution plus simple et qui fait bien le travail.
Pour compléter les blancs de la réponse de Dan Abramov, vous pouvez utiliser store.subscribe()
comme ceci:
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
Avant de créer le magasin, vérifiez localStorage
et analysez tous les JSON sous votre clé comme ceci:
const persistedState = localStorage.getItem('reduxState') ? JSON.parse(localStorage.getItem('reduxState')) : {}
Vous passez ensuite cette constante peristedState
à votre méthode createStore
comme ceci:
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
Dans un mot: middleware.
Départ redux-persist . Ou écrivez le vôtre.
[MISE À JOUR 18 décembre 2016] Édité pour supprimer la mention de deux projets similaires maintenant inactifs ou obsolètes.
Si vous rencontrez un problème avec les solutions ci-dessus, vous pouvez écrire le vôtre. Laisse-moi te montrer ce que j'ai fait. Ignorer saga middleware
les choses se concentrent simplement sur deux choses localStorageMiddleware
et reHydrateStore
, méthode. la localStorageMiddleware
tire tout le redux state
et le met dans local storage
et rehydrateStore
tire tous les applicationState
dans la mémoire locale si elle est présente et le met dans 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;
Je ne peux pas répondre à @Gardezi mais une option basée sur son code pourrait être:
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
)
);
la différence est que nous ne faisons que sauvegarder certaines actions. Vous pouvez même utiliser une fonction anti-rebond pour ne sauvegarder que la dernière interaction de votre état.
Je suis un peu en retard mais j'ai implémenté un état persistant selon les exemples donnés ici. Si vous souhaitez mettre à jour l'état uniquement toutes les X secondes, cette approche peut vous aider:
Définir une fonction wrapper
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!")
}
}
Appeler une fonction wrapper dans votre abonné
store.subscribe((state) =>
{
updateLocalStorage(store.getState())
});
Dans cet exemple, l'état est mis à jour au plus toutes les 5 secondes, quelle que soit la fréquence à laquelle une mise à jour est déclenchée.