An Introduction to React Redux (Part 2)

In my last post I delved into the simple case of using Redux as a flux implementation in my React app. It actually reduced the code that I had written with my own library (not including the library itself) by some 25%, which is immediately a win. However, it also had some problems. Firstly, it had done nothing to reduce the code in my React Component-View and I was really hoping to remove the boilerplate there. Secondly, it only handled simple actions. More complex actions (like async net requests) were just not handled. I had to actually work around this by calling dispatch within a promise to make it work – it certainly wasn’t as simple as dispatching an action.

Fortunately, Redux is flexible enough to handle both these issues. Since this is a big topic, I’m only going to cover the React Component changes this time round.

Updating Component Views

The core of the problem with React Component Views is that Flux doesn’t require you to use React. Sure, the two get mentioned in the same breath most of the time, but they are not really linked. React is a view component and Flux is an application state component. But you can swap out React for just basic Javascript if you like. There is nothing magical about it.

That being said, my application is React, so I need to adjust things according to React. Let’s start with the three data storage possibilities you have in a React component:

  • STATE is for stuff that never leaves the component.
  • PROPS is for introducing stuff from the parent component.
  • CONTEXT is for introducing stuff to a stack of components.

That last one is new in React 0.13 and will likely change significantly as the library moves towards a 1.0 release. However, it’s really useful for our needs – providing a store to all interested components. That brings us to react-redux – a companion library to Redux that knows about React. For our first step, I need to wrap the entire application in a Provider – the Provider changes the store into a context. You probably should just wrap the entire application, like this (in client/app.jsx):

import { StyleRoot } from 'radium';
import React from 'react';
import ReactDOM from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { Provider } from 'react-redux';

import store from './redux/store';
import PageView from './pageview.jsx';

// support tap events

let pageStyle = {
    bottom: 0,
    left: 0,
    margin: 0,
    padding: 0,
    position: 'fixed',
    right: 0,
    top: 0

// render the page
    <Provider store={store}>
        <StyleRoot style={pageStyle}>

Line 5 brings in the Provider component, line 7 brings in the store, and lines 25 and 29 are the wrapping I mentioned.

Now that I have the store available to everyone, what does a Component-View look like? Simple components (or, as they are often referred to, presentation components), like my LeftMenu.jsx component, don’t need any adjustments. A Component-View needs to be linked to the store. That happens by wrapping the component in react-redux additions. Let’s take a look. Note that this is not the complete listing – just the important parts, so ignore the line numbers:

import Radium from 'radium';
import React from 'react';
import { connect } from 'react-redux';
import AppBar from 'material-ui/lib/app-bar';
import IconButton from 'material-ui/lib/icon-button';
import LeftMenu from '../components/LeftMenu.jsx';

// Default Styles
import appStyle from '../style/appStyle';

class Chrome extends React.Component {
    static propTypes = {
        // Child page to be provided by react-router
        children: React.PropTypes.node,
        // Phase - provided by the Redux Store (connect call)
        phase: React.PropTypes.string.isRequired,
        // Error - provided by the Redux Store (connect call)
        error: React.PropTypes.string,
        // User - provided by the Redux Store (connect call)
        user: React.PropTypes.object

    static statusIcons = {
        pending: 'fa fa-spinner fa-pulse',
        error: 'mdi mdi-alert-octagon',
        anonymous: 'mdi mdi-login',
        authenticated: 'mdi mdi-logout'

    static stylesheet = {
        // The stylesheet is here

    constructor(props) {
        this.state = { leftMenu: { isOpen: false } }};

     * Event Handler - show or display the left menu
     * @param {bool} open if the left nav should be open or closed
     * @returns {bool} true if the event was handled
    onManipulateLeftMenu(open) {
        this.setState({ leftMenu: { isOpen: open } });

    render() {
        let errorIndicator = '';
        if (this.props.phase === 'error')
            errorIndicator = <div style={Chrome.stylesheet.error}>{this.props.error}</div>;

        // Properties for the AppBar component
        let iconClassName = Chrome.statusIcons[this.props.phase];
        let color = this.props.phase === 'error' ? '#ff0000' : '#ffffff';
        let appbarOptions = {
            iconElementRight: <IconButton iconStyle={{ color: color }} iconClassName={iconClassName} />,
            style: Chrome.stylesheet.appbar,
            title: 'Grumpy Wizards',
            onLeftIconButtonTouchTap: () => { return this.onManipulateLeftMenu(!this.state.leftMenu.isOpen); }

        // Properties for the LeftMenu component
        let leftMenuOptions = {
            open: this.state.leftMenu.isOpen,
            onRequestChange: (open) => { return this.onManipulateLeftMenu(open); }

        return logger.exit('render', (
            <div style={}>
                    <AppBar {...appbarOptions} />
                    <LeftMenu {...leftMenuOptions} />
                <section style={Chrome.stylesheet.mainpage}>
                <footer style={Chrome.stylesheet.footer}>
                    <h6 style={Chrome.stylesheet.footertext}>
                        {'Copyright \u00a9 2016 Adrian Hall'}

function select(state) {
    switch (state.phase) {
    case 'error':
        return {
            phase: state.phase,
            error: state.error
    case 'authenticated':
        return {
            phase: state.phase,
            user: state.user
        return {
            phase: state.phase

export default connect(select)(Chrome);

There is a lot going on here:

  • Line 3 brings in the connect method – more on that later
  • Lines 16-21 define the properties we are going to receive from the connect method
  • Lines 51-56 use this.props to access the store elements
  • Lines 90-107 define what is transitioned from the store to this.props
  • Line 109 links the store to this.props using the connect, wrapping the original class

The connect() method takes the store (which is provided using the React context) and copies the required store variables into React props. What is returned is a wrapped React component, which you can use anywhere you need to bring in this component. There are actually two (optional) arguments to the connect() method. The first is a method that tells connect what store elements to map to props. The second is a method that tells connect what store actions need to be dispatched. The latter allows you to incorporate actions directly using action creators. You can then use the action creators directly in your app. For instance, let’s say I have an action creator called adjustLeftMenu(open) that can replace the state of the left menu. Of course, this would require a reducer associated with it, but I’ve covered that last time. I can change the connect call to this:

export default connect(
    (state) => {
        return {
            phase: state.phase,
            user: state.user,
            error: state.error,
            leftMenuVisibility: state.leftMenuVisibility
    { adjustLeftMenu })(Chrome);

Once I’ve incorporated the action creator, I can do this:

        // Properties for the LeftMenu component
        let leftMenuOptions = {
            open: this.state.leftMenu.isOpen,
            onRequestChange: (open) => { this.props.dispatch(this.props.adjustLeftMenu(open)); }

In this case, you need to add dispatch to the list of propTypes.

Note that the majority of the state is gone. I can still use state, and I do for the show/hide of the left menu. Arguably, the state of the left menu is an application state, so I could move it into the Redux state store, but I don’t have to. The two lifecycle methods – componentWillMount() and componentWillUnmount() – are not required any more.

And, of course, my current source code is available on GitHub.