首页 > 解决方案 > Redux-Persist 不会将 store 保存到 localStorage

问题描述

Redux-Persist 不会将 store 保存到 localStorage,有人有什么想法吗?

store.js

import { createInjectorsEnhancer } from 'redux-injectors';
import { applyMiddleware, createStore } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import createSagaMiddleware from 'redux-saga';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import { createReducer } from './createReducer';

export function configureStore() {
  const sagaMiddleware = createSagaMiddleware();
  const middlewares = [sagaMiddleware];

  const persistConfig = {
    key: 'root',
    storage,
  };

  const enhancers = [
    applyMiddleware(...middlewares),
    createInjectorsEnhancer({
      createReducer,
      runSaga: sagaMiddleware.run,
    }),
  ];

  const persistedReducer = persistReducer(persistConfig, createReducer());
  const store = createStore(persistedReducer, {}, composeWithDevTools(...enhancers));
  const persistor = persistStore(store);

  return { store, persistor };
}

createReducer.js

import { combineReducers } from 'redux';

export function createReducer(injectedReducers = {}) {
  return combineReducers({
    ...injectedReducers,
  });
}

成分:

import { bindActionCreators, Dispatch } from 'redux';
import { ActionType } from 'typesafe-actions';
import { useEffect } from 'react';
import { createStructuredSelector } from 'reselect';
import { connect } from 'react-redux';
import { useInjectReducer, useInjectSaga } from 'redux-injectors';
import * as Actions from './actions';
import { ComponentReducer } from './reducer';
import { ComponentSaga } from './saga';

function Component({ }: ComponentProps) {
  useInjectReducer({ key: 'Component', reducer: ComponentReducer });
  useInjectSaga({ key: 'Component', saga: ComponentSaga });

  return <></>;
}

type ComponentProps- = {
   // types
};

const mapDispatchToProps = (dispatch: Dispatch<ActionType<typeof Actions>>) =>
  bindActionCreators(
    {
      // methods,
    },
    dispatch,
  );

const mapStateToProps = createStructuredSelector({
  // selectors
});

export default connect(mapStateToProps, mapDispatchToProps)(Component);

应用程序.js

import { Provider } from 'react-redux';
import { Router } from 'react-router';
import { PersistGate } from 'redux-persist/integration/react';
import App from './containers/App';
import { configureStore } from '../utils/configureStore';
import { history } from '../appHistory';

const { store, persistor } = configureStore();

ReactDOM.render(
  <React.StrictMode>
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <Router history={history}>
          <App />
        </Router>
      </PersistGate>
    </Provider>
  </React.StrictMode>,
  document.getElementById('root'),
);

它看起来像一个正常的应用程序结构,但它不起作用。我认为 90% 的问题在于带有 redux-injectors 的动态注入减速器。我试过用老方法注入之类的,但还是没用。

/**
 * Create the store with dynamic reducers
 */
import { createStore, applyMiddleware, compose } from 'redux';
import { fromJS } from 'immutable';
import { routerMiddleware } from 'connected-react-router/immutable';
import createSagaMiddleware from 'redux-saga';
import { persistStore, autoRehydrate } from 'redux-persist-immutable';
import createFilter from 'redux-persist-transform-filter-immutable';
import createReducer from './reducers';

const sagaMiddleware = createSagaMiddleware();

export default function configureStore(initialState = {}, history) {
  // Create the store with two middlewares
  // 1. sagaMiddleware: Makes redux-sagas work
  // 2. routerMiddleware: Syncs the location/URL path to the state
  const middlewares = [sagaMiddleware, routerMiddleware(history)];

  const enhancers = [applyMiddleware(...middlewares)];

  enhancers.push(autoRehydrate());
  // If Redux DevTools Extension is installed use it, otherwise use Redux compose
  /* eslint-disable no-underscore-dangle, indent */
  const composeEnhancers =
    process.env.NODE_ENV !== 'production' && typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
      ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true })
      : compose;
  /* eslint-enable */

  const store = createStore(createReducer(), fromJS(initialState), composeEnhancers(...enhancers));

  if (process.env.NODE_ENV !== 'test') {
    const stateFilter = createFilter('global', [
      'abonent',
      'version',
      'products',
      'showWorkSpaces',
      'error',
      'settings',
    ]);

    window.persistor = persistStore(store, {
      whitelist: ['global', 'sprinterSidebar'],
      transforms: [stateFilter],
    });
  }
  // Extensions
  store.runSaga = sagaMiddleware.run;
  store.injectedReducers = {}; // Reducer registry
  store.injectedSagas = {}; // Saga registry

  return store;
}

标签: javascriptreactjsreduxpersist

解决方案


就在上周,我发现自己遇到了类似的情况,就像你一样,我也在运行时注入了减速器,这就是我最终发现导致这个问题的原因。

persistor.persit()解决方法就是在注入新的reducer后调用该方法。您可能需要查看如何为redux-injectors您正在使用的库执行此操作。就我而言,我使用一个简单的函数来做到这一点:

/**
 * dynamically injects a reducer at runtime
 * @param key an identifier for this reducer
 * @param reducer The reducer
 * @param blacklist do not persist the reducer state
 */
const injectReducer = <RState>(key: string, reducer: Reducer<RState, AnyAction>, blacklist = false) => {
    if (!(key in asyncReducers)) {
        asyncReducers[key] = reducer;
        if (blacklist) {
            asyncBlacklist.push(key);
        }
        appStore.replaceReducer(createReducer(asyncReducers, asyncBlacklist));
        storeEvents.emit("root-reducer-change"); // or persistor.persist()
    }
};

storeEvents是一个EventEmitter3对象。

...这就是我注册监听器然后持久存储的地方:

export const store = { ...appStore, injectReducer };
export const persistor = persistStore(appStore);

storeEvents.on("root-reducer-change", () => persistor.persist());

另一个奇怪的(可能是最令人沮丧的)部分是为了理解发生了什么,安装了redux devtools 扩展似乎隐藏了这个问题。所以我对任何使用 redux 的开发者的建议是:

确保您在测试期间至少禁用一次 REDUX DEVTOOLS 扩展,否则您的应用程序的用户可能会遇到与您假设的应用程序不同的情况。

资料来源:


推荐阅读