Javascript 在Redux应用程序中写入本地存储的位置?
我想将状态树的某些部分持久化到本地存储。什么是这样做的合适地点?减速机还是动作?一句话:中间件 退房。或者写你自己的Javascript 在Redux应用程序中写入本地存储的位置?,javascript,redux,local-storage,state,Javascript,Redux,Local Storage,State,我想将状态树的某些部分持久化到本地存储。什么是这样做的合适地点?减速机还是动作?一句话:中间件 退房。或者写你自己的 【2016年12月18日更新】编辑以删除两个类似项目的提及,这两个项目现在处于非活动状态或已弃用状态。Reducer从来不是一个合适的地方,因为Reducer应该是纯的,并且没有副作用 我建议只在订阅服务器中执行此操作: store.subscribe(() => { // persist your state }) 创建存储之前,请阅读这些持久化部分: const
【2016年12月18日更新】编辑以删除两个类似项目的提及,这两个项目现在处于非活动状态或已弃用状态。
Reducer从来不是一个合适的地方,因为Reducer应该是纯的,并且没有副作用 我建议只在订阅服务器中执行此操作:
store.subscribe(() => {
// persist your state
})
创建存储之前,请阅读这些持久化部分:
const persistedState = // ...
const store = createStore(reducer, persistedState)
如果使用combineReducers()
您会注意到,未接收到状态的减速机将使用其默认状态
参数值正常“启动”。这很方便
建议您取消订阅服务器的缓冲,这样就不会太快地写入本地存储,否则会出现性能问题
最后,您可以创建一个中间件来封装它作为替代方案,但我会从订阅服务器开始,因为它是一个更简单的解决方案,而且做得很好。要填补Dan Abramov答案中的空白,您可以使用
store.subscribe()
如下所示:
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
在创建存储之前,请检查localStorage
,并按如下方式解析键下的任何JSON:
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
然后将此persistedState
常量传递给createStore
方法,如下所示:
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
如果任何人对上述解决方案有任何问题,您可以自己写信给。让我告诉你我做了什么。忽略
saga中间件
事情只关注两件事localStorageMiddleware
和reHydrateStore
方法。localStorageMiddleware
拉取所有redux状态
并将其放入local存储
和rehydrateStore
拉取本地存储中的所有applicationState
并将其放入redux存储
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;
从'redux'导入{createStore,applyMiddleware}
从“redux saga”导入createSagaMiddleware;
从“../reducers/decorist\u reducer”导入解相干减速机
从“../sagas/sagas”导入sagas;
const sagaMiddleware=createSagaMiddleware();
/**
*将所有状态添加到本地存储中
*@param getState
*@returns{function(*):function(*=)}
*/
const localStorageMiddleware=({getState})=>{//(action)=>{
常量结果=下一步(操作);
localStorage.setItem('applicationState',JSON.stringify(
getState()
));
返回结果;
};
};
const reHydrateStore=()=>{/我无法回答@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
)
);
不同之处在于,我们只是保存一些操作,您可以使用事件消除功能仅保存状态的最后一次交互我有点晚了,但根据此处所述的示例,我实现了一个持久状态。如果您只想每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秒更新一次,而不管更新的频率有多高。基于其他答案中提供的优秀建议和简短代码摘录(和),这里有一个完整的解决方案
我们需要一个包含2个函数的文件,用于将状态保存/加载到本地存储器或从本地存储器加载状态:
//文件:src/common/localStorage/localStorage.js
//传入Redux存储的状态以将其保存到用户的浏览器本地存储
导出常量保存状态=(状态)=>
{
尝试
{
const serializedState=JSON.stringify(state);
setItem('state',serializedState);
}
抓住
{
//我们将忽略写入错误
}
};
//加载状态并返回可作为
//store.js对configureStore的调用的preload状态参数
导出常量loadState=()=>
{
尝试
{
const serializedState=localStorage.getItem('state');
如果(serializedState==null)
{
返回未定义;
}
返回JSON.parse(serializedState);
}
捕获(错误)
{
返回未定义;
}
};
如果不需要将所有redux存储复制到localStorage,则可以使用特定的存储参数:
store.subscribe(()=>{
window.localStorage.setItem('currency', store.getState().lang)
})
并设置初始状态参数值,如下所示:
const initialState = {
currency: window.localStorage.getItem('lang') ?? 'en',
}
在这种情况下,您不需要将const persistedState
传递到const store=createStore()
我一直在寻找一个完整的示例,介绍如何使用redux toolkit persist将状态持久化到本地存储,但没有成功,直到我遇到上面的@canProm响应来解决我的问题。
这就是我的工作
//package.json
"reduxjs-toolkit-persist": "^7.0.1",
"lodash": "^4.17.21"
//localstorage.ts
import localStorage from 'reduxjs-toolkit-persist/es/storage';
export const saveState = (state: any) => {
try {
console.log(state);
const serializableState = JSON.stringify(state);
localStorage.setItem('globalState', serializableState);
} catch (err) {
console.log('Redux was not able to persist the state into the localstorage');
}
};
export const loadState = () => {
try {
const serializableState: string | any =
localStorage.getItem('globalState');
return serializableState !== null || serializableState === undefined ? JSON.parse(serializableState) : undefined;
} catch (error) {
return undefined;
}
};
//slices - actions
//reduxjs-toolkit-slices.ts
import { combineReducers, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { UserModel } from '../model/usermodel';
import { GlobalState } from './type';
const deaultState: GlobalState = {
counter: 0,
isLoggedIn: false
};
const stateSlice = createSlice({
name: "state",
initialState: deaultState,
reducers: {
isLoggedIn: (state, action: PayloadAction<boolean>) => {
console.log('isLogged');
console.log(state.isLoggedIn);
console.log(action);
state.isLoggedIn = action.payload;
console.log(state.isLoggedIn);
},
setUserDetails: (state, action: PayloadAction<UserModel>) => {
console.log('setUserDetails');
console.log(state);
console.log(action);
//state.userContext.user = action.payload;
}
}
});
//export actions under slices
export const {
isLoggedIn: isUserLoggedAction,
setUserDetails: setUserDetailActions
} = stateSlice.actions;
//TODO: use the optimal way for combining reducer using const
//combine reducer from all slice
export const combineReducer = combineReducers({
stateReducer: stateSlice.reducer
});
//storeConfig
//reduxjs-toolkit-store.ts
import { configureStore } from '@reduxjs/toolkit';
import { throttle } from 'lodash';
import { persistReducer } from 'reduxjs-toolkit-persist';
import autoMergeLevel2 from 'reduxjs-toolkit-persist/lib/stateReconciler/autoMergeLevel2';
import storage from 'reduxjs-toolkit-persist/lib/storage';
import { loadState, saveState } from './localStorage';
import { combineReducer } from './reduxjs-toolkit-slices';
// persist config
const persistConfig = {
key: 'root',
storage: storage,
stateReconciler: autoMergeLevel2,
};
const persistedReducer = persistReducer(persistConfig, combineReducer);
// export reducers under slices
const store = configureStore({
reducer: persistedReducer,
devTools: process.env.NODE_ENV !== 'production',
preloadedState: loadState(), //call loadstate method to initiate store from localstorage
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
thunk: true,
serializableCheck: false,
}),
});
// handle state update event. Whenever the state will change, this subscriber will call the saveState methode to update and persist the state into the store
store.subscribe(throttle(() => {
saveState(store.getState());
}, 1000));
export default store;
//App.ts
import { persistStore } from 'reduxjs-toolkit-persist';
import { PersistGate } from 'reduxjs-toolkit-persist/integration/react';
import './i18n';
let persistor = persistStore(store);
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={<div>Loading .....</div>} persistor={persistor}>
<HalocarburesRouter />
</PersistGate>
</Provider>,
document.getElementById('ingenierieMdn'));
//package.json
“reduxjs工具包持久化”:“^7.0.1”,
“lodash”:“^4.17.21”
//localstorage.ts
从“reduxjs工具包persist/es/storage”导入本地存储;
export const saveState=(状态:any)=>{
试一试{
console.log(状态);
const serializableState=JSON.stringify(state);
setItem('globalState',serializableState);
}捕捉(错误){
log('Redux无法将状态持久化到localstorage');
}
};
导出常量loadState=()=>{
试一试{
常量serializableState:字符串|任意=
getItem('globalState');
返回serializableState!==null | | serializableState===undefined?JSON.parse(serializableState):undefined;
}捕获(错误){
返回未定义;
}
};
//切片-动作
//reduxjs-toolkit-slices.ts
从'@reduxjs/toolkit'导入{combinereducer,createSlice,PayloadAction};
从“../model/UserModel”导入{UserModel};
从“./type”导入{GlobalState};
const deaultState:GlobalState={
柜台:0,,
伊斯洛格丁:错
};
const stateSlice=createSlice({
名称:“国家”,
initialState:deaultState,
减速器:{
isLoggedIn:(状态,操作:PayloadAction)=>{
console.log('isloged');
安慰