redux-router: Problem with dispatching pushState(...) using redux-thunk

I use redux-thunk which offers dispatch and getState in the action creator.

loginSuccess is a redux duck function which dispatches two actions, the second of which is pushState that is supposed to redirect to the attempted path after successful login.

export function loginSuccess(result) {
  return (dispatch, getState) => {
    dispatch({type: LOGIN_SUCCESS, result});
    const router = getState().router;
    dispatch(pushState(null, router.location.query.redirect))
  };
}

I can see an action of type @@reduxReactRouter/historyAPI is dispatched with this payload:

{"method": "pushState", "args": [null, "/path"]}

And nothing happens in the history!

However, when I dispatch the action creator in a component the route changes successfully and a @@reduxReactRouter/routeDidChange action is dispatched and everything is fine.

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 16 (1 by maintainers)

Most upvoted comments

@mohebifar This is the modified create.js

import { createStore as _createStore, applyMiddleware, compose } from 'redux';
import clientMiddleware from './middleware/clientMiddleware';
import transitionMiddleware from './middleware/transitionMiddleware';

export default function createStore(reduxReactRouter, getRoutes, createHistory, client, data) {

  const middleware = [clientMiddleware(client), transitionMiddleware];

  let finalCreateStore;

  if (__SERVER__) {
    finalCreateStore = compose(
      reduxReactRouter({ getRoutes, createHistory }),
      applyMiddleware(...middleware)
    )(_createStore);
  } else if (__CLIENT__ && __DEVELOPMENT__ && __DEVTOOLS__) {
    const { persistState } = require('redux-devtools');
    const DevTools = require('../containers/DevTools/DevTools');
    const logger = require('redux-logger')();
    finalCreateStore = compose(
      applyMiddleware(...middleware),
      reduxReactRouter({ getRoutes, createHistory }),
      applyMiddleware(logger),
      window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument(),
      persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
    )(_createStore);
  } else if (__CLIENT__) {
    finalCreateStore = compose(
      applyMiddleware(...middleware),
      reduxReactRouter({ getRoutes, createHistory })
    )(_createStore);
  }

  const reducer = require('./modules/reducer');
  const store = finalCreateStore(reducer, data);

  if (__DEVELOPMENT__ && module.hot) {
    module.hot.accept('./modules/reducer', () => {
      store.replaceReducer(require('./modules/reducer'));
    });
  }

  return store;
}

I also removed redux-thunk, and in clientMiddleware.js I did this:

export default function clientMiddleware(client) {
  return ({dispatch, getState}) => {
    return next => action => {
      if (typeof action === 'function') {
        return action(dispatch, getState, client);
      }

      const { promise, types, ...rest } = action; // eslint-disable-line no-redeclare
      if (!promise) {
        return next(action);
      }

      const [REQUEST, SUCCESS, FAILURE] = types;
      next({...rest, type: REQUEST});
      return promise(client).then(
        (result) => next({...rest, result, type: SUCCESS})
      ).catch((error)=> {
        console.error('MIDDLEWARE ERROR:', error);
        next({...rest, error, type: FAILURE});
      });
    };
  };
}

Added the client as a third parameter of the actions passed as a function… to be used like this in the action creator. eg. redux/modules/auth.js

export function login(email, password) {
  return (dispatch, getState, client) => {
    dispatch({ type: LOGIN });
    client.post('/api/auth/local', {
      data: { email, password }
    })
    .then(() => {
      dispatch({ type: LOGIN_SUCCESS });
      dispatch(load());
    })
    .catch((error) => {
      dispatch({ type: LOGIN_FAIL, error });
    });
  };
}

Cheers

@timaschew figured out… actually the issue was in the ordering of the middleware. thanks anyway