我想将我的状态树的某些部分持久化到localStorage。在什么地方这样做比较合适?减速还是行动?


当前回答

我无法回答@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
    )
);

不同之处在于我们只是保存了一些动作,你可以使用debounce函数来保存你状态的最后一次交互

其他回答

我无法回答@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
    )
);

不同之处在于我们只是保存了一些动作,你可以使用debounce函数来保存你状态的最后一次交互

一句话:中间件。

查看redux-persist。或者自己写。

[更新2016年12月18日]编辑删除提及两个类似的项目现在不活跃或弃用。

减速器从来不是一个合适的地方这样做,因为减速器应该是纯粹的,没有副作用。

我建议只在订阅者中进行:

store.subscribe(() => {
  // persist your state
})

在创建存储之前,读取那些持久化的部分:

const persistedState = // ...
const store = createStore(reducer, persistedState)

如果你使用combineReducers(),你会注意到那些没有接收到状态的reducer会像正常启动一样使用默认的state参数值。这非常方便。

建议您取消订阅服务器,这样就不会太快地写入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()