preloadedState - 会话结果被另一个reducer覆盖

时间:2017-12-04 12:31:35

标签: javascript reactjs redux

我有一个会话缩减器(使用redux-session库),它使用中间件从localstore恢复状态。我可以从调试工具中看到这是按预期工作的,但它正在被我的用户reducer的初始状态所取代。

我觉得我应该使用preloadedState,但是我无法将reducer的结果输入到createStore中?

正确恢复

storedState(我可以将其登录到控制台)。

session: {user: {data: bhBSh}}, user: {data: null} 

我无法看到在重新加载页面时将“会话”复制回“用户”的最佳方式?

会话缩减器:

function sessionReducer (state = {}, action) {
    switch (action.type) {
        case 'LOAD_STORED_STATE':
            console.log(action.storedState); //Working!!!!!
            return action.storedState;
        default:
            return state;
    }
}

用户缩减器:

import { fromJS } from 'immutable';

import {
    USER_LOGGING_IN,
  USER_LOGGED_IN,
  USER_LOGGED_OUT,
} from '../../constants';

const userInitialState = fromJS({
    data: null,
    isLoading: false,
});

function userReducer(state = userInitialState, action) {
    switch (action.type) {
        case USER_LOGGING_IN:
            return state
                .set('isLoading', true);
        case USER_LOGGED_IN:
            return state
                .set('data', action.payload)
                .set('isLoading', false);
        case USER_LOGGED_OUT:
            return userInitialState;
        default:
            return state;
    }
}

export default userReducer;

export default function createReducer(injectedReducers) {
  return combineReducers({
      session: sessionReducer,
      user: userReducer,

    ...injectedReducers,
  });
}

configureStore:

export default function configureStore(history, session) {
      session,
    routerMiddleware(history),
      thunkMiddleware
  ];

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

  //compose enhancers removed for readability 

  const store = createStore(
    createReducer(),
    //preloaded state??
    composeEnhancers(...enhancers)
  );

  store.injectedReducers = {}; // Reducer registry  

  return store;
}     

app.js

/**
 * app.js
 *
 * This is the entry file for the application, only setup and boilerplate
 * code.
 */

// Needed for redux-saga es6 generator support
import 'babel-polyfill';

// Import all the third party stuff
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import FontFaceObserver from 'fontfaceobserver';
import createHistory from 'history/createBrowserHistory';
import { createSession } from 'redux-session';
import 'sanitize.css/sanitize.css';

// Import root app
import App from 'containers/App';

// Import Language Provider
import LanguageProvider from 'containers/LanguageProvider';

// Load the favicon, the manifest.json file and the .htaccess file
/* eslint-disable import/no-webpack-loader-syntax */
import '!file-loader?name=[name].[ext]!./images/favicon.ico';
import '!file-loader?name=[name].[ext]!./images/icon-72x72.png';
import '!file-loader?name=[name].[ext]!./images/icon-96x96.png';
import '!file-loader?name=[name].[ext]!./images/icon-120x120.png';
import '!file-loader?name=[name].[ext]!./images/icon-128x128.png';
import '!file-loader?name=[name].[ext]!./images/icon-144x144.png';
import '!file-loader?name=[name].[ext]!./images/icon-152x152.png';
import '!file-loader?name=[name].[ext]!./images/icon-167x167.png';
import '!file-loader?name=[name].[ext]!./images/icon-180x180.png';
import '!file-loader?name=[name].[ext]!./images/icon-192x192.png';
import '!file-loader?name=[name].[ext]!./images/icon-384x384.png';
import '!file-loader?name=[name].[ext]!./images/icon-512x512.png';
import '!file-loader?name=[name].[ext]!./manifest.json';
import 'file-loader?name=[name].[ext]!./.htaccess'; // eslint-disable-line import/extensions
/* eslint-enable import/no-webpack-loader-syntax */

import configureStore from './configureStore';

// Import i18n messages
import { translationMessages } from './i18n';

// Import CSS reset and Global Styles
import './global-styles';

// Observe loading of Open Sans (to remove open sans, remove the <link> tag in
// the index.html file and this observer)
const openSansObserver = new FontFaceObserver('Open Sans', {});

// When Open Sans is loaded, add a font-family using Open Sans to the body
openSansObserver.load().then(() => {
  document.body.classList.add('fontLoaded');
}, () => {
  document.body.classList.remove('fontLoaded');
});

// Create redux store with history
const history = createHistory();
const session = createSession({
    ns: 'test001',
    selectState (state) {
        return {
            user: state.toJS().user
        };
    }
});

const store = configureStore(history, session);
const MOUNT_NODE = document.getElementById('app');

const render = (messages) => {
  ReactDOM.render(
    <Provider store={store}>
      <LanguageProvider messages={messages}>
        <ConnectedRouter history={history}>
          <App />
        </ConnectedRouter>
      </LanguageProvider>
    </Provider>,
    MOUNT_NODE
  );
};

if (module.hot) {
  // Hot reloadable React components and translation json files
  // modules.hot.accept does not accept dynamic dependencies,
  // have to be constants at compile-time
  module.hot.accept(['./i18n', 'containers/App'], () => {
    ReactDOM.unmountComponentAtNode(MOUNT_NODE);
    render(translationMessages);
  });
}

// Chunked polyfill for browsers without Intl support
if (!window.Intl) {
  (new Promise((resolve) => {
    resolve(import('intl'));
  }))
    .then(() => Promise.all([
      import('intl/locale-data/jsonp/en.js'),
      import('intl/locale-data/jsonp/de.js'),
    ]))
    .then(() => render(translationMessages))
    .catch((err) => {
      throw err;
    });
} else {
  render(translationMessages);
}

// Install ServiceWorker and AppCache in the end since
// it's not most important operation and if main code fails,
// we do not want it installed
if (process.env.NODE_ENV === 'production') {
  require('offline-plugin/runtime').install(); // eslint-disable-line global-require
}

1 个答案:

答案 0 :(得分:1)

redux-session docs可以看出,此库尝试恢复已保存状态的唯一方法是调度LOAD_STORED_STATE(可以自定义)操作。在调度操作时恢复您的状态取决于您。恢复user状态的最简单方法是在userReducer中处理此操作,以便它看起来像:

function userReducer(state = userInitialState, action) {
    switch (action.type) {
        case LOAD_STORED_STATE:
            return fromJS(action.storedState);
        case USER_LOGGING_IN:
            return state
                .set('isLoading', true);
        case USER_LOGGED_IN:
            return state
                .set('data', action.payload)
                .set('isLoading', false);
        case USER_LOGGED_OUT:
            return userInitialState;
        default:
            return state;
    }
}