Pierwszą zasadą dokumentacji Redux jest:
Stan całej aplikacji jest przechowywany w drzewie obiektów w jednym magazynie.
Pomyślałem, że dobrze rozumiem wszystkie zasady. Ale teraz nie wiem, co oznacza aplikacja.
Jeśli aplikacja to tylko jedna z mało skomplikowanych części witryny i działa tylko na jednej stronie, rozumiem. A co, jeśli aplikacja oznacza całą witrynę? Czy powinienem używać LocalStorage lub cookie, czy czegoś innego do utrzymania drzewa stanu? ale co, jeśli przeglądarka nie obsługuje LocalStorage?
Chcę wiedzieć, jak deweloperzy zachowują swoje drzewo stanów! :)
Odpowiedzi:
Jeśli chcesz zachować swój stan Redux podczas odświeżania przeglądarki, najlepiej to zrobić za pomocą oprogramowania pośredniczącego Redux. Sprawdź oprogramowanie pośredniczące redux-persist i redux-storage . Obaj próbują wykonać to samo zadanie, czyli przechowywać stan redux, aby można go było zapisywać i ładować do woli.
-
Edytować
Minęło trochę czasu, odkąd wróciłem do tego pytania, ale widząc, że druga (choć bardziej pozytywna odpowiedź) zachęca do wprowadzenia własnego rozwiązania, pomyślałem, że odpowiem ponownie.
Od tej edycji obie biblioteki zostały zaktualizowane w ciągu ostatnich sześciu miesięcy. Mój zespół od kilku lat używa Redux-persist w produkcji i nie miał żadnych problemów.
Chociaż może się to wydawać prostym problemem, szybko przekonasz się, że wprowadzenie własnego rozwiązania nie tylko spowoduje obciążenie konserwacyjne, ale także spowoduje błędy i problemy z wydajnością. Pierwsze przychodzące na myśl przykłady to:
JSON.stringify
iJSON.parse
może nie tylko obniżyć wydajność, gdy nie jest potrzebna, ale także generować błędy, które nieobsługiwane w krytycznym fragmencie kodu, takim jak sklep redux, mogą spowodować awarię aplikacji.Podsumowując, dla 3kB minified + gzipped (w czasie tej edycji) nie jest to problem, który prosiłbym mój zespół o samodzielne rozwiązanie.
źródło
Edytuj 25 sierpnia 2019 r
Jak stwierdzono w jednym z komentarzy. Oryginalny pakiet Redux-Storage został przeniesiony do React -stack . To podejście nadal koncentruje się na wdrażaniu własnego rozwiązania do zarządzania stanem.
Oryginalna odpowiedź
Chociaż udzielona odpowiedź była prawidłowa w pewnym momencie, należy zauważyć, że oryginalny pakiet redux-storage został przestarzały i nie jest już obsługiwany ...
Teraz, jeśli nie chcesz mieć zależności od innych pakietów, aby uniknąć takich problemów w przyszłości, bardzo łatwo jest stworzyć własne rozwiązanie.
Wystarczy, że:
1- Utwórz funkcję, która zwraca stan z,
localStorage
a następnie przekazuje stan docreateStore
funkcji redux w drugim parametrze w celu nawodnienia sklepuconst store = createStore(appReducers, state);
2- Nasłuchuj zmian stanu i za każdym razem, gdy stan się zmienia, zapisz stan
localStorage
store.subscribe(() => { //this is just a function that saves state to localStorage saveState(store.getState()); });
I to wszystko ... Właściwie używam czegoś podobnego w produkcji, ale zamiast korzystać z funkcji napisałem bardzo prostą klasę jak poniżej ...
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 } }; } }
a następnie podczas ładowania aplikacji ...
import StateLoader from "./state.loader" const stateLoader = new StateLoader(); let store = createStore(appReducers, stateLoader.loadState()); store.subscribe(() => { stateLoader.saveState(store.getState()); });
Mam nadzieję, że to komuś pomoże
Uwaga dotycząca wydajności
Jeśli zmiany stanu są bardzo częste w aplikacji, zbyt częste zapisywanie w magazynie lokalnym może zaszkodzić wydajności aplikacji, zwłaszcza jeśli wykres obiektu stanu do serializacji / deserializacji jest duży. W takich przypadkach warto opóźnieniu na przepustnicy lub funkcję, która zapisuje stan na localStorage użyciu
RxJs
,lodash
lub coś podobnego.źródło
Jest to oparte na odpowiedzi Leo (która powinna być zaakceptowaną odpowiedzią, ponieważ osiąga cel pytania bez korzystania z bibliotek innych firm).
Stworzyłem klasę Singleton, która tworzy Redux Store, utrzymuje go przy użyciu lokalnej pamięci i umożliwia prosty dostęp do swojego magazynu poprzez getter .
Aby go użyć, po prostu umieść następujący element Redux-Provider wokół swojej głównej klasy:
// ... Your other imports import PersistedStore from "./PersistedStore"; ReactDOM.render( <Provider store={PersistedStore.getDefaultStore().store}> <MainClass /> </Provider>, document.getElementById('root') );
i dodaj następującą klasę do swojego projektu:
import { createStore } from "redux"; import rootReducer from './RootReducer' const LOCAL_STORAGE_NAME = "localData"; class PersistedStore { // Singleton property static DefaultStore = null; // Accessor to the default instance of this class static getDefaultStore() { if (PersistedStore.DefaultStore === null) { PersistedStore.DefaultStore = new PersistedStore(); } return PersistedStore.DefaultStore; } // Redux store _store = null; // When class instance is used, initialize the store constructor() { this.initStore() } // Initialization of Redux Store initStore() { this._store = createStore(rootReducer, PersistedStore.loadState()); this._store.subscribe(() => { PersistedStore.saveState(this._store.getState()); }); } // Getter to access the Redux store get store() { return this._store; } // Loading persisted state from localStorage, no need to access // this method from the outside static loadState() { try { let serializedState = localStorage.getItem(LOCAL_STORAGE_NAME); if (serializedState === null) { return PersistedStore.initialState(); } return JSON.parse(serializedState); } catch (err) { return PersistedStore.initialState(); } } // Saving persisted state to localStorage every time something // changes in the Redux Store (This happens because of the subscribe() // in the initStore-method). No need to access this method from the outside static saveState(state) { try { let serializedState = JSON.stringify(state); localStorage.setItem(LOCAL_STORAGE_NAME, serializedState); } catch (err) {} } // Return whatever you want your initial state to be static initialState() { return {}; } } export default PersistedStore;
źródło