Transition to another route on successful async redux action

If you don't want to use a more complete solution like Redux Router, you can use Redux History Transitions which lets you write code like this:

export function login() {
  return {
    type: LOGGED_IN,
    payload: {
      userId: 123
    }
    meta: {
      transition: (state, action) => ({
        path: `/logged-in/${action.payload.userId}`,
        query: {
          some: 'queryParam'
        },
        state: {
          some: 'state'
        }
      })
    }
  };
}

This is similar to what you suggested but a tiny bit more sophisticated. It still uses the same history library under the hood so it's compatible with React Router.


I ended up creating a super simple middleware that roughtly looks like that:

import history from "../routes/history";

export default store => next => action => {

    if ( ! action.redirect ) return next(action);

    history.replaceState(null, action.redirect);
}

So from there you just need to make sure that your successful actions have a redirect property. Also note, this middleware does not trigger next(). This is on purpose as a route transition should be the end of the action chain.


For those that are using a middleware API layer to abstract their usage of something like isomorphic-fetch, and also happen to be using redux-thunk, you can simply chain off your dispatch Promise inside of your actions, like so:

import { push } from 'react-router-redux';
const USER_ID = // imported from JWT;

function fetchUser(primaryKey, opts) {
    // this prepares object for the API middleware
}

// this can be called from your container
export function updateUser(payload, redirectUrl) {
    var opts = {
        method: 'PUT',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(payload)
    };
    return (dispatch) => {
        return dispatch(fetchUser(USER_ID, opts))
            .then((action) => {
                if (action.type === ActionTypes.USER_SUCCESS) {
                    dispatch(push(redirectUrl));
                }
            });
    };
}

This reduces the need for adding libraries into your code as suggested here, and also nicely co-locates your actions with their redirects as done in redux-history-transitions.

Here is what my store looks like:

import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers';
import thunk from 'redux-thunk';
import api from '../middleware/api';
import { routerMiddleware } from 'react-router-redux';

export default function configureStore(initialState, browserHistory) {
    const store = createStore(
        rootReducer,
        initialState,
        applyMiddleware(thunk, api, routerMiddleware(browserHistory))
    );

    return store;
}