Redux 文档的第一原则是:
整个应用程序的状态存储在单个存储中的对象树中。
我实际上认为我很好地理解了所有的原则。但我现在很困惑,申请是什么意思。
如果应用程序只是网站中的一个小复杂部分并且只在一页中工作,我理解。但是如果应用程序意味着整个网站呢?我应该使用 LocalStorage 还是 cookie 或其他东西来保存状态树?但是如果浏览器不支持 LocalStorage 呢?
我想知道开发人员如何保持他们的状态树!:)
Redux 文档的第一原则是:
整个应用程序的状态存储在单个存储中的对象树中。
我实际上认为我很好地理解了所有的原则。但我现在很困惑,申请是什么意思。
如果应用程序只是网站中的一个小复杂部分并且只在一页中工作,我理解。但是如果应用程序意味着整个网站呢?我应该使用 LocalStorage 还是 cookie 或其他东西来保存状态树?但是如果浏览器不支持 LocalStorage 呢?
我想知道开发人员如何保持他们的状态树!:)
如果你想在浏览器刷新时保持你的 redux 状态,最好使用 redux 中间件来做到这一点。查看redux-persist和redux-storage中间件。它们都试图完成存储您的 redux 状态的相同任务,以便可以随意保存和加载它。
——
编辑
自从我重新审视这个问题已经有一段时间了,但是看到另一个(尽管更多的赞成的答案)鼓励推出您自己的解决方案,我想我会再次回答这个问题。
截至本次编辑时,这两个库均已在过去六个月内更新。我的团队已经在生产中使用 redux-persist 几年了,并且没有出现任何问题。
虽然这似乎是一个简单的问题,但您很快就会发现,推出自己的解决方案不仅会造成维护负担,还会导致错误和性能问题。想到的第一个例子是:
JSON.stringify
并且JSON.parse
不仅会在不需要时损害性能,而且会抛出错误,如果在诸如 redux store 之类的关键代码中未处理,可能会使您的应用程序崩溃。总而言之,对于 3kB 缩小 + gzipped(在此编辑时),这不是问题,我会要求我的团队自行解决。
如其中一条评论所述。原始的redux-storage包已移至react-stack。这种方法仍然侧重于实现您自己的状态管理解决方案。
虽然提供的答案在某些时候是有效的,但重要的是要注意原始redux-storage包已被弃用并且不再维护......
包 redux-storage 的原作者决定弃用该项目,不再维护。
现在,如果您不想依赖其他软件包以避免将来出现此类问题,那么推出您自己的解决方案非常容易。
您需要做的就是:
1- 创建一个函数,该函数返回状态localStorage
,然后将状态传递给createStore
第二个参数中的 redux 函数,以便对 store 进行水化
const store = createStore(appReducers, state);
2- 监听状态变化,每次状态变化时,将状态保存到 localStorage
store.subscribe(() => {
//this is just a function that saves state to localStorage
saveState(store.getState());
});
就是这样......我实际上在生产中使用了类似的东西,但是我没有使用函数,而是编写了一个非常简单的类,如下所示......
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
}
};
}
}
然后在引导您的应用程序时...
import StateLoader from "./state.loader"
const stateLoader = new StateLoader();
let store = createStore(appReducers, stateLoader.loadState());
store.subscribe(() => {
stateLoader.saveState(store.getState());
});
希望它可以帮助某人
如果应用程序中的状态更改非常频繁,那么过于频繁地保存到本地存储可能会损害应用程序的性能,尤其是当要序列化/反序列化的状态对象图很大时。对于这些情况,您可能希望去抖动或油门,使用保存状态的localStorage功能RxJs
,lodash
或类似的东西。
这是基于 Leo 的答案(这应该是公认的答案,因为它在不使用任何 3rd 方库的情况下达到了问题的目的)。
我创建了一个 Singleton 类,它创建了一个 Redux Store,使用本地存储将它持久化,并允许通过 getter 简单访问其存储。
要使用它,只需在主类周围放置以下 Redux-Provider 元素:
// ... Your other imports
import PersistedStore from "./PersistedStore";
ReactDOM.render(
<Provider store={PersistedStore.getDefaultStore().store}>
<MainClass />
</Provider>,
document.getElementById('root')
);
并将以下类添加到您的项目中:
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;