我想将我的状态树的某些部分持久化到localStorage。在什么地方这样做比较合适?减速还是行动?
当前回答
为了填补Dan Abramov的答案,你可以像这样使用store.subscribe():
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
在创建存储之前,检查localStorage并像这样解析键下的JSON:
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
然后你像这样将这个perstedstate常量传递给你的createStore方法:
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)
其他回答
如果你不需要复制所有redux store到localStorage,你可以使用特定的store参数:
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'));
减速器从来不是一个合适的地方这样做,因为减速器应该是纯粹的,没有副作用。
我建议只在订阅者中进行:
store.subscribe(() => {
// persist your state
})
在创建存储之前,读取那些持久化的部分:
const persistedState = // ...
const store = createStore(reducer, persistedState)
如果你使用combineReducers(),你会注意到那些没有接收到状态的reducer会像正常启动一样使用默认的state参数值。这非常方便。
建议您取消订阅服务器,这样就不会太快地写入localStorage,否则就会出现性能问题。
最后,您可以创建一个中间件,将其封装为替代方案,但我会从订阅者开始,因为这是一个更简单的解决方案,而且工作做得很好。
我有点晚了,但是我根据这里的示例实现了一个持久状态。如果你想每X秒更新一次状态,这个方法可以帮助你:
Define a wrapper function 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!") } } Call a wrapper function in your subscriber store.subscribe((state) => { updateLocalStorage(store.getState()) });
在这个例子中,状态最多每5秒更新一次,而不管更新被触发的频率。
为了填补Dan Abramov的答案,你可以像这样使用store.subscribe():
store.subscribe(()=>{
localStorage.setItem('reduxState', JSON.stringify(store.getState()))
})
在创建存储之前,检查localStorage并像这样解析键下的JSON:
const persistedState = localStorage.getItem('reduxState')
? JSON.parse(localStorage.getItem('reduxState'))
: {}
然后你像这样将这个perstedstate常量传递给你的createStore方法:
const store = createStore(
reducer,
persistedState,
/* any middleware... */
)