如何更新 LocalStorage 中持久化的 Redux 状态结构
Posted
技术标签:
【中文标题】如何更新 LocalStorage 中持久化的 Redux 状态结构【英文标题】:How To Update Structure of Redux State Persisted In LocalStorage 【发布时间】:2019-05-12 17:13:36 【问题描述】:我将一部分 Redux 状态保存在 localStorage 中,以便在页面刷新时保持它。
如果我的 Redux 状态结构发生变化,如何更新 localStorage 中的状态结构?
示例:
这是我的 combineReducer 文件:
// combineReducer
const rootReducer = combineReducers(
usersPage: usersPageReducer,
form: formReducer
)
我的 usersPageReducer 中的原始默认状态如下所示:
// usersPageReducer.js
defaultUsersPageState =
selectedColumns: ["name", "email"],
我使用以下方法加载并保存到 localStorage:
// localStorage.js
export const loadState = () =>
try
const serializedState = localStorage.getItem('state')
if (serializedState === null)
return undefined;
return JSON.parse(serializedState)
catch (err)
return undefined
export const saveState = (state) =>
try
const serializedState = JSON.stringify(state)
localStorage.setItem('state', serializedState)
catch (err)
// to define
在我的主文件中,我订阅了商店,并保存了状态的usersPage
切片。我使用来自 localStorage 的初始状态创建商店:
// main.js
const persistedState = loadState();
const initialState = ...persistedState ;
const store = createStore(
rootReducer,
initialState,
);
store.subscribe(() =>
saveState(
usersPage: store.getState().usersPage
)
)
现在假设我想更改我的 usersPageReducer
默认状态,以便它也跟踪排序。
// usersPageReducer.js
defaultUsersPageState =
selectedColumns: ["name", "email"],
sorting: "name": "asc"
上述方法不起作用,因为在应用程序启动时,我们从 localStorage 中对 redux 初始状态进行了水合。旧的初始状态击败了 usersPageReducer defaultUsersPageState
。
由于 localStorage 不知道 usersPageReducer
的 sorting
键,并且我们从不使用默认状态,因此 sorting
键永远不会添加到 redux 状态。
有没有办法对 redux 存储进行水合,以便它使用默认状态初始化每个 reducer(好像我们没有使用 localStorage),然后传播存储的状态?
【问题讨论】:
您可以通过将默认状态与缓存状态深度合并来创建初始状态。这样做会将新值添加到旧的缓存状态。 我将在哪里进行合并?我是否必须将每个减速器的默认状态导入我的main.js
文件?在这种情况下,将defaultUsersPageState
导入main.js
?这似乎无法在我的大型应用程序中扩展。
【参考方案1】:
有两个可能的解决方案我可以建议你:-
1. 使用变量来跟踪应用程序的版本(更好的是 redux-version )。现在,每当更改此变量的值时,您的应用程序将清除用户的 LocalStorage
并使用 defaultUsersPageState
提供的全新的 redux 结构(或其子部分),而不是而不是从中加载可用的(陈旧的)数据。
你可以通过多种方式实现这一点,我的是
// localStorage.js
export const loadState = (CurrVersion) =>
try
// check if version matches or not ...
// for first time localStorage.getItem('appVersion') will be null
if (CurrVersion !== localStorage.getItem('appVersion'))
localStorage.removeItem('state') //
// update the appVersion in LS with current version
localStorage.setItem('appVersion', CurrVersion)
return undefined;
else
const serializedState = localStorage.getItem('state')
if (serializedState === null)
return undefined;
return JSON.parse(serializedState)
catch (err)
return undefined
在main.js
// change it whenever breaking changes are added and it makes sense
const CurrVersion = 'MY-APP-VERSION-2.0'
const persistedState = loadState(CurrVersion);
const initialState = ...persistedState ;
const store = createStore(
rootReducer,
initialState,
);
store.subscribe(() =>
saveState(
usersPage: store.getState().usersPage
)
)
-
明确检查持久化数据的结构是否更改。如果更改,您可以删除以前的对象并使用已更新结构的默认初始状态。但请记住,此检查需要递归地(或深度地)完成,您可能会发现 lodash 对此很有用。
P.S:如果你有大项目,请使用为这个问题构建的 npm
包,例如 react-persist
。
【讨论】:
以上是关于如何更新 LocalStorage 中持久化的 Redux 状态结构的主要内容,如果未能解决你的问题,请参考以下文章
Next.js 具有 React 钩子和 localStorage 的持久状态
如何将 localStorage 与 apollo-client 和 reactjs 一起使用?