Changing React Route Programmatically with Redux-Saga

last updated: Jun 5th, 2017

Sometimes in a web app you've got a workflow that calls for a route change after a user action. For example, suppose the user has to complete a form and click a button. The data is sent to the server via AJAX and then you'd like to redirect the user to a another page upon successful transmission.

Redux

First, let's set up some action creators

actions.js

export const ActionTypes = {    SEND_DATA_REQUEST: 'SEND_DATA_REQUEST',    SEND_DATA_SUCCESS: 'SEND_DATA_SUCCESS',    SEND_DATA_FAILURE: 'SEND_DATA_FAILURE',};export const sendDataRequest = details => ({    type: ActionsTypes.SEND_DATA_REQUEST,    payload: details,});export const sendDataSuccess = user => ({    type: ActionTypes.SEND_DATA_SUCCESS,    payload: user,});export const sendDataFailure = err => ({    type: ActionTypes.SEND_DATA_FAILURE,    payload: err,    error: true,});

Note: The reducer is omitted because it's unnecessary for this example.

React

Your react component looks something like this:

myForm.jsx

import * as React from 'react';import { connect } from 'react-redux';import { sendDataRequest } from './actions';export class MyFormComponent extends React.Component {    submitForm = () => {        const data = /* ... */;        this.props.onSubmit(data);    };    render() {        return (            <form onSubmit={ this.submitForm }>                {/*  */}            </form>        );    }};const mapStateToProps = state => ({    // ...});const mapDispatchToProps = dispatch => ({    onSubmit: data => dispatch(sendDataRequest(data)),});export const MyForm = connect(mapStateToProps, mapDispatchToProps)(MyFormComponent);

Redux-Saga

React-router-redux exposes action creators, push, replace, go, goForward, and goBack, that perform navigation. We're going to use the push action creator to navigate to a new location.

sendDataSaga.js

import { push } from 'react-router-redux';import { apiPost } from './apiClient';import {    ActionTypes, sendDataSuccess, sendDataFailure} from './actions';export function* sendDataSaga() {    while (true) {        // Wait for user to submit the form        const data = yield take(ActionTypes.SEND_DATA_REQUEST);        let response;        try {            // Send the data to the server and get a response back            response = yield call(apiPost, '/api/data', data);        }        catch (err) {            // Report errors to our store            yield put(sendDataFailure(err));            continue;        }        // Report success to our store and redirect to another page        yield put(sendDataSuccess(response));        yield put(push('/next-page'));    }}

Further Reading

Building asynchronous web applications is complicated. React with Redux is not enough. You need something like Redux-Saga to complete the picture.

I can show you how. Sign up on my email list where I write about Redux-Saga and related web development topics.