Philip C
Philip C

Reputation: 61

react-router-redux: doesn't update history after SECOND route change

I created an app that is largely based on react-boilerplate.

But for some reason after the second route change via the LOCATION_CHANGE redux action, the history object doesn't get updated with the new location.

The URL changes to match the new location and the redux store is updated to reflect the route change, but the history object still shows the previous location as the current location. I've been trying to solve this problem for days now and I'm sure it's something trivial that I'm completely overlooking.

Here's my routes.js file:

export function createRoutes(store) {
  // create reusable async injectors using getAsyncInjectors factory
  const { injectReducer, injectSagas } = getAsyncInjectors(store);


 // injectReducer('global', globalReducer);
  injectSagas(globalSagas);

  let routes = [
    {
      path: '/',
      name: 'dashboard',
      getComponent(nextState, cb) {
        const importModules = Promise.all([
          require('App/views/Main/state/reducer'),
          require('App/views/Main'),
        ]);

        const renderRoute = loadModule(cb);

        importModules.then(([reducer, component]) => {
          injectReducer('dashboard', reducer.default);
          renderRoute(component);
        });

        importModules.catch(errorLoading);
      },
      indexRoute: {
        getComponent(nextState, cb) {
            const importModules = Promise.all([
              require('App/views/Main/views/Posts/state/reducer'),
              require('App/views/Main/views/Posts/state/sagas'),
              require('App/views/Main/views/Posts'),
            ]);

            const renderRoute = loadModule(cb);

            importModules.then(([reducer, sagas, component]) => {
            //  injectReducer('posts', reducer.default);
            //  injectSagas(sagas.default);
              renderRoute(component);
            });

            importModules.catch(errorLoading);
          }
      },
      childRoutes: [
        {
          path: 'library',
          name: 'library',
          getComponent(nextState, cb) {
            const importModules = Promise.all([
              require('App/views/Main/views/MediaItemLibrary'),
            ]);

            const renderRoute = loadModule(cb);

            importModules.then(([component]) => {
              renderRoute(component);
            });

            importModules.catch(errorLoading);
          },
        },
        {
          path: 'calendar',
          name: 'calendar',
          getComponent(nextState, cb) {
            const importModules = Promise.all([
              require('App/views/Main/views/Calendar'),
            ]);

            const renderRoute = loadModule(cb);

            importModules.then(([component]) => {
              renderRoute(component);
            });

            importModules.catch(errorLoading);
          },
        }
      ],
    }, 
    {
      path: '/start',
      name: 'start',
      getComponent(nextState, cb) {
        const importModules = Promise.all([
          require('App/views/Start'),
        ]);

        const renderRoute = loadModule(cb);

        importModules.then(([component]) => {

          renderRoute(component);
        });

        importModules.catch(errorLoading);
      },
      indexRoute: {
        getComponent(nextState, cb) {
          const importModules = Promise.all([
            require('App/views/Start/views/Login/state/reducer'),
            require('App/views/Start/views/Login/state/sagas'),
            require('App/views/Start/views/Login'),
          ]);

          const renderRoute = loadModule(cb);

          importModules.then(([reducer, sagas, component]) => {
          //  injectReducer('login', reducer.default);
          //  injectSagas(sagas.default);

            renderRoute(component);
          });

          importModules.catch(errorLoading);
        },
      },
      childRoutes: [
        {
          path: '/signup',
          name: 'signup',
          getComponent(nextState, cb) {
            const importModules = Promise.all([
              require('App/views/Start/views/Signup/state/reducer'),
              require('App/views/Start/views/Signup/state/sagas'),
              require('App/views/Start/views/Signup'),
            ]);

            const renderRoute = loadModule(cb);

            importModules.then(([reducer, sagas, component]) => {
            //  injectReducer('signup', reducer.default);
            //  injectSagas(sagas.default);

              renderRoute(component);
            });

            importModules.catch(errorLoading);
          },
        }
      ],      
    }
  ];

  return {
    component: App,
    //indexRoute: { onEnter: (nextState, replace) => replace('/dashboard') },
    childRoutes: routes
  };
}

Here's the entry point to the app:

import 'babel-polyfill';

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { applyRouterMiddleware, Router, browserHistory, createBrowserHistory } from 'react-router';
import { useScroll } from 'react-router-scroll';
import { syncHistoryWithStore } from 'react-router-redux';
import injectTapEventPlugin from 'react-tap-event-plugin';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';

//Needed for material-ui libarry
injectTapEventPlugin();

// import sanitize css
import 'sanitize.css/sanitize.css';

import configureStore from './config.redux/store';

// import selector for 'syncHistoryWithStore'
import { makeSelectLocationState } from './config.redux/selectors';
// root app
import App from './App';

import { createRoutes} from 'config.routes/routes';

export const historyObj = browserHistory;

// create redux store with history
const initialState = {};
const store = configureStore(initialState, historyObj);
// sync history and store, as the react-router-redux reducer
const history = syncHistoryWithStore(historyObj, store, {
    selectLocationState: makeSelectLocationState(),
});

const rootRoute = createRoutes(store);

ReactDOM.render(
    <Provider store={store}>
        <MuiThemeProvider>
            <Router
                history={history}
                routes={rootRoute}
                //render={
                    // Scroll to top when going to new page, imitating default browser behavior
                    //applyRouterMiddleware(useScroll())
               // }
            />
        </MuiThemeProvider>
    </Provider>, document.getElementById('app')
);

Any idea what could be causing this? Thanks so much

Upvotes: 2

Views: 454

Answers (1)

Philip C
Philip C

Reputation: 61

So after a ton of headache I figured out the issue. A freaking typo.

My router location select was:

  // merge route into the global application state
  function routeReducer(state = routeInitialState, action) {
      switch(action.type) {
        case LOCATION_CHANGE:
            return state.merge({
                locationBeforeTransition: action.payload,
            });
        default:
            return state;
      }
  }

    export {
        makeSelectLocationState
    };

and the correct version is:

  // merge route into the global application state
  function routeReducer(state = routeInitialState, action) {
      switch(action.type) {
        case LOCATION_CHANGE:
            return state.merge({
                locationBeforeTransitions: action.payload,
            });
        default:
            return state;
      }
  }

That missed 's' on locationBeforeTransition cost me nearly two days of lost time...

Upvotes: 1

Related Questions