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;
}