Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

preloadedState - session result overwritten by another reducer

I have a session reducer (using the redux-session library) which uses middleware to recover the state from the localstore. I can see from debugging tools that this is working as intended, however it is being replaced by my user reducer's initial state.

I feel I should be using preloadedState, but I cant get the result of a reducer into createStore?

storedState is being restored correctly (I can log it into console).

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

I cant see the best way to copy 'session' back to 'user' when the page is reloaded?

Session reducer:

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

User reducer:

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
}
like image 271
Codematcha Avatar asked Dec 04 '17 12:12

Codematcha


1 Answers

As you can see from redux-session docs, the only thing this library tries to do to restore saved state is dispatching LOAD_STORED_STATE (which can be customized) action. Restoring your state when the action is dispatched is up to you. The simplest way to restore user state is to handle this action in your userReducer, so that it will look something like:

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;
    }
}
like image 112
fkulikov Avatar answered Nov 18 '22 21:11

fkulikov