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');
    安慰