Using Azure Mobile Apps from a React Redux App

I did some work towards my React application in my last article – specifically handling authentication with Auth0 providing the UI and then swapping the token with Azure Mobile Apps for a ZUMO token. I’m now all set to do some CRUD operations within my React Redux application. There is some basic Redux stuff in here, so if you want a refresher, check out my prior Redux articles:

Refreshing Data

My first stop is “how do I get the entire table that I can see from Azure Mobile Apps?” This requires multiple actions in a React Redux world. Let’s first of all look at the action creators:

import constants from '../constants/tasks';
import zumo from '../../zumo';

/**
 * Internal Redux Action Creator: update the isLoading flag
 * @param {boolean} loading the isLoading flag
 * @returns {Object} redux-action
 */
function updateLoading(loading) {
    return {
        type: constants.UpdateLoadingFlag,
        isLoading: loading
    };
}

/**
 * Internal Redux Action Creator: replace all the tasks
 * @param {Array} tasks the new list of tasks
 * @returns {Object} redux-action
 */
function replaceTasks(tasks) {
    return {
        type: constants.ReplaceTasks,
        tasks: tasks
    };
}

/**
 * Redux Action Creator: Set the error message
 * @param {string} errorMessage the error message
 * @returns {Object} redux-action
 */
export function setErrorMessage(errorMessage) {
    return {
        type: constants.SetErrorMessage,
        errorMessage: errorMessage
    };
}

/**
 * Redux Action Creator: Refresh the task list
 * @returns {Object} redux-action
 */
export function refreshTasks() {
    return (dispatch) => {
        dispatch(updateLoading(true));

        const success = (results) => {
            console.info('results = ', results);
            dispatch(replaceTasks(results));
        };

        const failure = (error) => {
            dispatch(setErrorMessage(error.message));
        };

        zumo.table.read().then(success, failure);
    };
}

Four actions for a single operation? I’ve found this is common for Redux applications that deal with backend services – you need to have several actions to implement all the code-paths. I could have gotten away with just three – an initiator, a successful completion and an error condition. However, I wanted to ensure I had flexibility. The setErrorMessage() and updateLoading() actions are generic enough to be re-used for other actions.

Two of these actions are internal – I don’t export them and so the rest of the application never sees them. The only action creator that the application at large can use is the refreshTasks() action – the initiator for the refresh. I’ve made the setErrorMessage() task generic enough that it can be used by an error dialog to clear the error as well. Lesson learned – only export the tasks that you want the rest of the application to use.

Looking at the refreshTasks() task list, I’m not doing any filtering. Azure Mobile Apps supports filtering on the server as well as the client. I’d rather filter on the client in this application – it saves a round trip and the data is never going to be big enough that filtering is going to be a problem. This may not be true in your application – you should make a decision on filtering on the server. vs. client in terms of performance and memory usage.

Insert, Modify and Delete Tasks

I’ve already got the actions – I just need to update them for the async server code. For example, here is the insert code:

/**
 * Redux Action Creator: Insert a new task into the cache
 * @param {Object} task the task to be updated
 * @param {string} task.id the ID of the task
 * @param {string} task.text the description of the task
 * @param {bool} task.complete true if the task is completed
 * @returns {Object} redux-action
 */
function insertTask(task) {
    return {
        type: constants.Create,
        task: task
    };
}

/**
 * Redux Action Creator: Create a new Task
 * @param {string} text the description of the new task
 * @returns {Object} redux-action
 */
export function createTask(text) {
    return (dispatch) => {
        dispatch(updateLoading(true));

        const newTask = {
            text: text,
            complete: false
        };

        const success = (insertedItem) => {
            console.info('createTask: ', insertedItem);
            dispatch(insertTask(insertedItem));
        };

        const failure = (error) => {
            dispatch(setErrorMessage(error.message));
        };

        zumo.table.insert(newTask).then(success, failure);
    };
}

I’m reusing the updateLoading() and setErrorMessage() action creators that I used with the refresh tasks. The createTask() does the insert async then calls the insertTask() action creator with the newly created task to update the in-memory cache (as we will see below when we come to the reducers). There are similar mechanisms for modification and deletion. I create an internal action creator to update the in-memory cache. The exported action creator initiates the change and doesn’t update the in-memory cache until the request is completed successfully.

I did need to do some work to add a dialog on the error message being set in my Application.jsx component:

        const onClearError = () => { return dispatch(taskActions.setErrorMessage(null)); };
        let errorDialog = <div style={{ display: 'none' }}/>;
        if (this.props.errorMessage) {
            const actions = [ <FlatButton key="cancel-dialog" label="OK" primary={true} onTouchTap={onClearError} /> ];
            errorDialog = (
                <Dialog
                    title="Error from Server"
                    actions={actions}
                    modal={true}
                    open={true}
                    onRequestClose={onClearError}
                >
                    {this.props.errorMessage}
                </Dialog>);
        }

I then place {errorDialog} in my rendered JSX file.

Adjusting the Cache

Let’s take a look at the reducers.

import constants from '../constants/tasks';

const initialState = {
    tasks: [],
    profile: null,
    isLoading: false,
    authToken: null,
    errorMessage: null
};

/**
 * Reducer for the tasks section of the redux implementation
 *
 * @param {Object} state the current state of the tasks area
 * @param {Object} action the Redux action (created by an action creator)
 * @returns {Object} the new state
 */
export default function reducer(state = initialState, action) {
    switch (action.type) {
    case constants.StoreProfile:
        return Object.assign({}, state, {
            authToken: action.token,
            profile: action.profile
        });

    case constants.UpdateLoadingFlag:
        return Object.assign({}, state, {
            isLoading: action.isLoading
        });

    case constants.Create:
        return Object.assign({}, state, {
            isLoading: false,
            tasks: [ ...state.tasks, action.task ]
        });

    case constants.ReplaceTasks:
        return Object.assign({}, state, {
            isLoading: false,
            tasks: [ ...action.tasks ]
        });

    case constants.Update:
        return Object.assign({}, state, {
            isLoading: false,
            tasks: state.tasks.map((tmp) => { return tmp.id === action.task.id ? Object.assign({}, tmp, action.task) : tmp; })
        });

    case constants.Delete:
        return Object.assign({}, state, {
            isLoading: false,
            tasks: state.tasks.filter((tmp) => { return tmp.id !== action.taskId; })
        });

    case constants.SetErrorMessage:
        return Object.assign({}, state, {
            isLoading: false,
            errorMessage: action.errorMessage
        });

    default:
        return state;
    }
}

You will note that my reducers only deal with the local cache. I could, I guess, also store this in localStorage so that my restart speed is faster. There would be a more complex interaction between the server, the in-memory cache and the localStorage cache that would have to be sorted out, however.

Note that all my reducers that result in a change to the in-memory cache also turn off the isLoading flag. This allows me one less dispatch via redux. I doubt it’s a significant performance increase, but I’m of the opinion that any obvious performance wins should be done. In this case, each operation results in one less action dispatch and one less Object.assign. In bigger projects, this could be significant.

Thinking about Sync and Servers

One of the things you can clearly see in this application is the delay in the round-trip to the server. I don’t update the cache until I have updated the server. This is safe. However, it’s hardly performant. There are a couple of ways I could fix this.

Firstly, I can update the local cache first. For example, let’s say I am inserting a new object. I can add two new local fields that are not transmitted to the server: clientId and isDirty. When the task is newly created, I can create a clientId instead (and use that everywhere) and set the dirty flag. When the server response comes back, I update the record from the server (not updating clientId) and clear the dirty flag. This allows me to identify “things that have not been updated on the server”, perhaps preventing multiple updates – it also allows me to identify things that have been newly created on the client.

Secondly, I can update a localStorage area instead of the server. This will be much faster. Then, periodically, I can trigger a refresh of the data from the server – sending the changes to the localStorage area up to the server.

There are multiple ways to do synchronization of data with a server – which one depends on the requirements of accuracy of the data on the server, performance required on the client and memory consumption. There are trade offs whichever way you choose.

Where’s the code

You can find the complete code on my GitHub Repository.

React, Redux and Routing

In the process of dealing with my application, I’ve got a curious combination. My React application is using react-router to handle page transitions within the single-page application. It does this by putting the page that is currently being shown in the hash of the location. As a result, the pages end up looking like http://localhost:3000/#/home?q=982hihu.

However, I’m using Redux as my application state store. The idea is that all my application state is in the state store. Except for the react-router state – that is stored in the location hash.

This is obviously less than ideal. I want my application state to be in the redux store – not in other places. More importantly, this is something that others have had to deal with as well as there are packages out there that handle this situation. I’m going to integrate the react-router with Redux using react-router-redux.

Step 1: Update the Store

First off, install the react-router-redux package:

npm install --save-dev react-router-redux

Now update the client/redux/store.js with the code necessary to integrate the library:

import { createStore, combineReducers, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';
import promiseMiddleware from 'redux-promise';
import { createHistory } from 'history';
import { syncHistory, routerReducer } from 'react-router-redux';

import { requestAuthInfo } from './redux/actions/auth';
import * as reducers from './redux/reducers';

// Combine the reducers for the store
const appReducers = combineReducers({
    ...reducers,
    routing: routerReducer
});

// Move the react-router stuff into Redux
export const history = createHistory();
const reduxRouterMiddleware = syncHistory(history);

// Apply all the middleware for Redux
const middlewares = applyMiddleware(
    reduxRouterMiddleware,
    thunkMiddleware,
    promiseMiddleware,
    createLogger()
);

// Create the Redux Store
export const store = reduxStore(appReducers, middlewares);
// reduxRouterMiddleware.listenForReplays(store);

// Dispatch the initial action
store.dispatch(requestAuthInfo());

There are a couple of wrinkles here. Firstly, you may not be familiar with using spread operators to combine objects. Let’s say I have the following:

const a = { b: 1, c: 2 };
const d = {
    ...a
    d: 3
};
// d === { b: 1, c: 2, d: 3 };

This is an excellent way of merging objects with ES2015 shorthand. The result is that I have three reducers – the two I provide and the routeReducer that react-router-redux provides.

The second wrinkle is that I actually need to link history to both the Router object and to the store. it’s the go-between for the two pieces.

After those two wrinkles, the store set up is fairly simple. I’m intending on setting up replay at some point so I’ve put a reminder to listen for replays for the store. It’s not important or needed right now.

Step 2: Update the Router

My main app.jsx file contains the router. I’ve updated it to listen to the exported history object from the store:

import React from 'react';
import ReactDOM from 'react-dom';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { Provider } from 'react-redux';
import { Router } from 'react-router';
import { StyleRoot } from 'radium';
import AppRoutes from './pages';
import { store, history } from './redux/store';

// Needed for onTouchTap - Can go away when react 1.0 release
// Check this repo: https://github.com/zilverline/react-tap-event-plugin
injectTapEventPlugin();

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

let onUpdate = () => { window.scrollTo(0, 0); };

// render the page
ReactDOM.render(
    <Provider store={store}>
        <StyleRoot style={pageStyle}>
            <Router history={history} onUpdate={onUpdate}>
                {AppRoutes}
            </Router>
        </StyleRoot>
    </Provider>,
    document.getElementById('pageview')
);

This code is fairly simple. Line 8 brings in both the store and the history that we export from the redux/store.js module. Line 30 links the router to our redux-enabled history object.

Step 3: Update the routing actions

Normally, one would use LinkTo from the react-router object to update the route. With redux in the mix, one will dispatch an action to update the routing context. Here is the Home.jsx component view that shows the general form of the new linkage:

import Radium from 'radium';
import React from 'react';
import { connect } from 'react-redux';
import { routeActions } from 'react-router-redux';

@Radium
class Home extends React.Component {
    /**
     * React property types
     * @type {Object}
     * @readonly
     */
    static propTypes = {
        dispatch: React.PropTypes.func.isRequired,
        phase: React.PropTypes.string.isRequired
    };

    /**
     * Render the component
     * @returns {JSX.Element} the rendered component
     * @overrides React.Component#render
     */
    render() {
        const dispatch = this.props.dispatch;
        const page1 = () => { return dispatch(routeActions.push('/page1')); };

        return (
            <div id="homePage">
                <h1>{'Home'}</h1>
                <ul>
                    <li><button onClick={page1}>Page 1</button></li>
                </ul>
            </div>
        );
    }
}

/*
** Link the Chrome component to the Redux store
*/
export default connect(
    (state) => {
        return {
            phase: state.auth.phase
        };
    })(Home);

Line 4 brings in the routeActions – a set of action creators provided by the react-router-redux library. The main action creator here is push which pushes the requested route onto the history and hence changes the page that you are on.

A Small Issue – the page route

One of the small issues I had was in the reload case. Let’s say I go to http://localhost:3000 – this loads my application, exactly as expected. then I click on the Home page – this changes the URL to http://localhost:3000/home and the home page is displayed. If I then click the reload button, I get an error message.

The problem is that the route (without the hash) is sent to the server and the server does not know how to handle it. Basically, I need to ensure that any unknown routes cause the server to load the initial page. This is done in my server/static/index.js module – this module serves my home page:

var config = require('config');
var express = require('express');
var fs = require('fs');
var path = require('path');
var serveStatic = require(`./static.${config.get('env')}.js`);

var fileContents = {};
var router = express.Router(); // eslint-disable-line new-cap

/**
 * Load the specified HTML file, caching the contents
 * in the fileContents object.
 * @param {string} filename the file name to load
 * @returns {string} the contents of the file
 */
function loadHtmlFile(filename) {
    var contents = '', file = path.join(__dirname, filename);
    if (!Object.hasOwnProperty(fileContents, filename)) {
        contents = fs.readFileSync(file, 'utf8'); // eslint-disable-line no-sync
        fileContents[filename] = contents
            .replace(/\$\{config.base\}/g, config.get('base'))
            .replace(/\$\{config.env\}/g, config.get('env'))
            .replace(/\$\{config.library.font-awesome}/g, config.get('library.font-awesome'))
            .replace(/\$\{config.library.mdi}/g, config.get('library.mdi'))
            .replace(/\$\{config.library.core-js}/g, config.get('library.core-js'))
            ;
    }
    return fileContents[filename];
}

// Home Page
router.get('/', (request, response) => {
    return response
        .status(200)
        .type('text/html')
        .send(loadHtmlFile('index.html'));
});

// Service static files - different for dev vs. prod
serveStatic(router);

// Ensure that anything not routed is captured here
router.get(/.*/, (request, response) => {
    return response
        .status(200)
        .type('text/html')
        .send(loadHtmlFile('index.html'));
});

module.exports = router;

The highlighted lines get called AFTER everything else. This means that anything that isn’t already responded to will return the home page. Of course, this means that if you go to http://localhost:3000/foo (or any other page that doesn’t have a route), then you will get a blank page unless you have a default route. Have a default route. You can do this easily in your route definition:

const routes = (
    <Route path="/" component={Chrome}>
        <IndexRoute component={Home}/>
        <Route path="home" component={Home}/>
        <Route path="page1" component={PageOne}/>
        <Redirect path="*" to="/" />
    </Route>
);

The Redirect needs to be the very last route. It basically says “anything that hasn’t already been matched, redirect to the home page”. Pretty cool.

Wrap Up

Another day – another React library. I like the modularity, but I’m thinking that there must be a Yeoman generator or something to enable a lot of this scaffolding code. I’m just cringing at adding yet another module or library to my code.

However, that’s reality in the React world. As always, my code is on my GitHub Repository.

An Introduction to React & Redux (Part 4)

I’ve been investigating Redux recently. If you missed the first three parts:

Thus far, my application is simple. I have some authentication related tasks and a UI related task. It’s currently no problem that all the state, actions and reducers are intermingled. However, this will become a problem as I move forward – more state elements and more actions will mean that I can’t rely on a flat structure. Today, I’m going to create two parts to my store – an auth section and a UI section.

Step 1: Set up action constants

As I grow, I will want to ensure that my action types are all unique, but still give a naming scheme that makes sense. To ensure this happens, I am going to use a separate constants.js file:

export default {
    ui: {
        leftMenuVisibility: 'ui.leftMenuVisibility'
    },
    auth: {
        setAnonymous: 'auth.setAnonymous',
        setAuthenticated: 'auth.setAuthenticated',
        setError: 'auth.setError'
    }
};

I’ve just made the string equal to the object path (or how I would access that string). This means that logging functions will display something reasonable. I, of course, need to update all the action creators:

import constants from './constants';

/**
 * Redux Action Creator for toggling left menu visibility
 * @param {bool} open the requested state of the left menu
 * @returns {Object} Redux Action
 */
export function displayLeftMenu(open) {
    return {
        type: constants.ui.leftMenuVisibility,
        visibility: open
    };
}

Repeat with all the action creators.

Step 2: Split up the Reducers

I’ve got a reducers.js file right now. I want to split them up. Create a reducers directory. The reducers/ui.js file will contain the reducer for the UI actions:

import constants from '../constants';

const initialState = {
    leftMenuVisibility: false
};

/**
 * Redux Reducer for UI manipulation
 *
 * @param {Object} state the initial state
 * @param {Object} action the Redux Action object
 * @returns {Object} the new state
 */
export default function uiReducer(state = initialState, action) {
    if (action.type === constants.ui.leftMenuVisibility) {
        return Object.assign({}, state, {
            leftMenuVisibility: action.visibility
        });
    }
    return state;
}

There are two things to note here. Firstly, the uiReducer only handles the state for the UI. Secondly, I am using an ES2015 default parameter to set the state of the UI and that only includes the state of the UI. Similarly, the reducers/auth.js only handles authentication:

import constants from '../constants';

const initialState = {
    phase: 'pending',
    user: null,
    error: null
};

export default function authReducer(state = initialState, action) {
    switch (action.type) {
    case constants.auth.setAnonymous:
        return Object.assign({}, state, {
            phase: 'anonymous',
            user: null,
            error: null
        });

    case constants.auth.setAuthenticated:

        let claims = action.providerInfo.user_claims.reduce((target, claim) =&gt; {
            target[claim.typ] = claim.val;
            if (claim.typ.indexOf('http://schemas.xmlsoap.org/ws') !== -1)
                target[claim.typ.slice(claim.typ.lastIndexOf('/') + 1)] = claim.val;
            return target;
        });

        let user = {
            accessToken: action.providerInfo.access_token,
            claims: claims,
            givenname: claims.givenname || '',
            name: claims.name || '',
            id: action.providerInfo.user_id,
            provider: action.providerInfo.provider_name,
            providerToken: action.providerInfo.authentication_token,
            surname: claims.surname || ''
        };

        return Object.assign({}, state, {
            phase: 'authenticated',
            user: user,
            error: null
        });

    case constants.auth.setError:
        return Object.assign({}, state, {
            phase: 'error',
            user: null,
            error: action.error.message
        });

    default:
        return state;
    }
}

I need to bring these together, so I’ve created a reducers/index.js with the following contents:

import ui from './ui';
import auth from './auth';

module.exports = {
    auth: auth,
    ui: ui
};

Don’t forget to remove reducers.js so that the new stuff is imported when you import ./reducers.

Step 3: Update the Store to combine reducers

I’ve updated the action creators to use constants, then split the reducers. Now I need to combine the reducers. Here are the updates to the redux/store.js file:

import { createStore, combineReducers, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import rdxThunk from 'redux-thunk';
import rdxPromise from 'redux-promise';
import { requestAuthInfo } from './actions';
import * as reducers from './reducers';

// Combine the reducers for the store
const appReducers = combineReducers(Object.assign({},
    reducers
));

// Create the Redux Store
const store = reduxStore(
    appReducers,
    applyMiddleware(rdxThunk, rdxPromise, createLogger())
);

// Dispatch the initial action
store.dispatch(requestAuthInfo());

export default store;

The important pieces here are the reducers. In line 6, I’m importing all the reducers that are exported via reducers/index.js. Lines 9-11 then combine all those reducers into one. Note that the initialState has been moved to the reducers – this allows each reducer file to handle its own state.

Step 4: Update the Component Views

Things will breack pretty dramatically if you run this project. However, running it will give you an idea of the new structure of the store. It’s now a heirarchy:

{
    "auth": { "error": null, "phase": "anonymous", "user": null },
    "ui": { "leftMenuVisibility": false }
}

The component views need to compensate for this new store format. This is mostly done in the propTypes object plus the connect call. Here are the new propTypes for components/Chrome.jsx:

    static propTypes = {
        auth: React.PropTypes.shape({
            error: React.PropTypes.string,
            phase: React.PropTypes.string.isRequired,
            user: React.PropTypes.object
        }),
        children: React.PropTypes.node,
        dispatch: React.PropTypes.func.isRequired,
        ui: React.PropTypes.shape({
            leftMenuVisibility: React.PropTypes.bool.isRequired
        })
    };

Note that I’ve described the auth and ui store properties precisely. I also need to update the connect() call:

export default connect(
    (store) => {
        return {
            auth: store.auth,
            ui: {
                leftMenuVisibility: store.ui.leftMenuVisibility
            }
        };
    })(Chrome);

I am probably not going to add more fields to the auth store, but I am extremely likely to add things to the ui store. As a result, I’ve described precisely what I need in the component. This matches what I’ve done in the propTypes. All I need to do once this is done is alter the references within the compoennt to the right props. For example, this.props.phase becomes this.props.auth.phase.

Wrap Up

This may seem like a small change and unnecessary complication right now, but organization is important as the application grows and this puts me on the appropriate track. I’m also splitting up the action creators in the same way. That allows me to expand the Redux store as required.

You can find the latest code at my GitHub Repository. Want to check out the differences? Just compare to the prior commit:

git diff 2016-03-01 2016-03-04

This will give you all the differences. You can compare this release to the prior one on the github repository by clicking here.

An Introduction to React Redux (Part 3)

In the past two articles, I’ve looked at Redux as an implementation of the flux architecture and I’ve looked at wrapping React components so that they can take advantage of Redux without a lot of boilerplate code. However, I had noted one issue – async actions. Redux action creators need to return an object that describes the action. When you deal with async actions, the thing that is returned is generally a Promise these days. It most definitely is not an object that you can immediately dispatch.

Personally, I think this is a complete failure of Redux. Async operations are the cornerstone of server-client communication and the decision to defer this functionality to another library is really a problem. It’s a problem I can live with, but I shouldn’t have to.

Now that I’ve got that off my chest, let’s take a look at the facility that allows Redux to handle async functions – middleware. You’ve probably seen middleware before – ExpressJS, for example, relies on middleware to handle even the most basic functionality. The concept within Redux is the same thing. We insert a function in between the action and the reducer to transform the action into a form that the reducer can digest.

Even though my app does not make use of a major amount of server-side API right now, I want to solve this because I expect a large amount of communication between backend and frontend and I want to be able to handle the async requests the same way as the simpler synchronous requests.

Let’s take another look at my Promise-based action creator:

export function requestAuthInfo() {
    return (dispatch) => {
        let fetchOptions = {
            method: 'GET',
            credentials: 'include',
            cache: 'no-cache',
            mode: 'cors'
        };
        return fetch(`${baseUrl}/.auth/me`, fetchOptions)
        .then((response) => {
            if (!response.ok && response.status !== 401)
                throw new Error(`Invalid Response from ${baseUrl}/.auth/me:`, response);
            if (response.status === 401)
                return new Promise((resolve) => { resolve(false); });
            return response.json();
        })
        .then((response) => {
            if (!response)
                dispatch(receiveAnonymousAuth());
            else
                dispatch(receiveAuthenticatedAuth(response));
        })
        .catch((error) => {
            dispatch(receiveErrorCondition(error));
        });
    };
}

Theoretically, I can just create an action and then call the action, like this:

// Dispatch the initial action
let requestAction = requestAuthInfo();
requestAction(store.dispatch);

However, I normally use dispatch like this:

store.dispatch(requestAuthInfo());

Fortunately, you don’t actually have to write your own middleware. Today I’m going to introduce three pieces of middleware. We’ll get to the main attraction shortly, but first let’s take a look at how middleware works by implementing some dispatch logging. The redux-logger middleware will log the actions dispatched and provide information about the before and after state. To implement this, we alter our store:

import { createStore, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import { requestAuthInfo } from './actions';
import reducer from './reducers';

const initialState = {
    phase: 'pending',
    user: null,
    error: null,
    leftMenuVisibility: false
};

const logger = createLogger();
const store = createStore(
    reducer, 
    initialState, 
    applyMiddleware(logger)
);

// Dispatch the initial action
let requestAction = requestAuthInfo();
requestAction(store.dispatch);

export default store;

UPDATE Based on advice from the Redux author – Dan Abramov – I’ve updated this sample.

The applyMiddleware() function takes a list of middleware functions – this is appended to the end of the createStore() paraeters so that the middleware is applied to the store. Note that the logger middleware must be placed last – otherwise you get wierd logs for actions that need to be transformed. If you run this project, you might get something like the following in the console window:

redux-logger-example

Each action is grouped and you see the before and after. This gives me a confidence that my components are doing the right thing – another ad-hoc test capability when doing development.

On to the meat of my problem though – how do I handle promises and functions in general? The answer is to use a thunk.

A what? Who makes up these terms? Seriously. Ok, let me break it down. A thunk is an action creator that returns a function instead of an object. My requestAuthInfo() action creator uses an arrow function which is basically a function, so I definitely need this. The middleware for this is called redux-thunk. That just handles the function mechanism though – I also need to handle the fact that the function returns a promise. That’s handled by redux-promise. Let me add all that to my redux/store.js:

import { createStore, applyMiddleware } from 'redux';
import createLogger from 'redux-logger';
import thunk from 'redux-thunk';
import reduxPromise from 'redux-promise';
import { requestAuthInfo } from './actions';
import reducer from './reducers';

const initialState = {
    phase: 'pending',
    user: null,
    error: null,
    leftMenuVisibility: false
};

const reduxLogger = createLogger();

const store = createStore(
    reducer,
    initialState,
    applyMiddleware(thunk, reduxPromise, reduxLogger)
);

// Dispatch the initial action
store.dispatch(requestAuthInfo());

export default store;

UPDATE Dan Abramov (who wrote redux) updated me to show the more JS-friendly way of doing this, and I love the new syntax. I have updated the syntax above to match what Dan is recommending now.

We need to order the middleware so that they are executed in the right order. The thunk handles the action creator that returns a function; the reduxPromise handles the case when the function returns a Promise, and finally, reduxLogger logs the before and after of the store state. I can now change the request for authentication information (line 24) to be a dispatched action.

Back on my soap-box. The redux-thunk and redux-promise libraries should just be incorporated into the createStore() call – they should not really be separate functions – async connectivity is core to most web apps.

It won’t stop me from using Redux. Remember when I started – my code was 214 lines long (not including the library code). This code is 167 lines long. In addition to the 25% reduction in actual code I have to write, there is also a reduction in boilerplate code that I have to write to use the store. That’s in addition to the fact that I don’t have to maintain my own library that doesn’t do half of what Redux does. All in all, I’d be happy if Redux stopped here. But it doesn’t.

As always, my code is available at my GitHub Repository. Since I updated the code after I published, please note that the code in the repo is different (see store.js)

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
injectTapEventPlugin();

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

// render the page
ReactDOM.render(
    <Provider store={store}>
        <StyleRoot style={pageStyle}>
            <PageView/>
        </StyleRoot>
    </Provider>,
document.getElementById('pageview'));

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

@Radium
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) {
        super(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={Chrome.stylesheet.chrome}>
                {errorIndicator}
                <header>
                    <AppBar {...appbarOptions} />
                    <LeftMenu {...leftMenuOptions} />
                </header>
                <section style={Chrome.stylesheet.mainpage}>
                    {this.props.children}
                </section>
                <footer style={Chrome.stylesheet.footer}>
                    <h6 style={Chrome.stylesheet.footertext}>
                        {'Copyright \u00a9 2016 Adrian Hall'}
                    </h6>
                </footer>
            </div>
        ));
    }
}

function select(state) {
    switch (state.phase) {
    case 'error':
        return {
            phase: state.phase,
            error: state.error
        };
    case 'authenticated':
        return {
            phase: state.phase,
            user: state.user
        };
    default:
        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.

An Introduction to React Redux (Part 1)

I’m on vacation right now, enjoying skiing by day at the lovely town and resort of Breckenridge. I did give myself something to do over the vacation, though. Ever since I was convinced of the flux architecture, I’ve been using my own simple flux library. It’s basically using the Facebook dispatcher, but my own store implementation that is tied into component views using the componentWillMount and componentWillUnmount methods of the React API. It works and it is simple.

I’m not a fan of building a new wheel just because one can, though. If I am to maintain my own library, then it must offer something that no other library can. In the case of my flux library, that isn’t the case. It’s at the bottom of a pack of flux implementations. In addition, every single list of things that React programmers can learn is to use Redux. Redux is the flux implementation at the top of the list if you look at popularity. So I set myself a task of learning React Redux over my vacation.

My requirements are very simple – I have a single API that receives authentication information from the server. I need to initiate the request to the server and then handle the response. I have two actions in my application right now – one to do the request and one to handle the response. My code is just 214 lines of code, but it has lots of side effects. Let’s see how it goes.

With apologies to Dan Abramov – I’m sure he (and several others) will cringe as I go through this…

Step 1: Action Creators

An action is an object with a type field and potentially some associated data. Something like this:

{ type: 'AUTH-ANONYMOUS' }
{ type: 'AUTH-AUTHENTICATED', providerInfo: response }
{ type: 'AUTH-ERROR', error: error.message }

If you follow most standard flux implementations, they will tell you to create a function that dispatches the action. Redux doesn’t do that. Instead you create an Action Creator that returns an action. It isn’t dispatched (yet). This philosophy changes when we discuss async functions. However, let’s create some action creators. I’ve created a directory called redux where I am going to store all the implementation details. In there, I have an action.js that will hold my action creators:

/**
 * Redux Action Creator for handling anonymous response
 * @returns {Object} Redux Action
 */
function receiveAnonymousAuth() {
    return {
        type: 'AUTH-ANONYMOUS'
    };
}

/**
 * Redux Action Creator for handling authenticated response
 * @param {Array} response the response from the server
 * @returns {Object} Redux Action
 */
function receiveAuthenticatedAuth(response) {
    return {
        type: 'AUTH-AUTHENTICATED',
        providerInfo: response[0]
    };
}

/**
 * Redux Action Creator for handling error conditions
 * @param {Error} the error that happened
 * @returns {Object} Redux Action
 */
function receiveErrorCondition(error) {
    return {
        type: 'AUTH-ERROR',
        error: error
    };
}

These are internal actions – I am not expecting my application UI to initiate these actions. I do not export these functions because they are internal. We’ll get onto the linkage eventually. Right now there is one action creator for each of my potential results – authenticated, anonymous and error. I’ve merged all three cases in my existing code which isn’t the best, so take the opportunity to refactor the code into something more maintainable as well.

Redux suggests that you have a big list of constants for the type. However, they are just strings – in smaller applications (like mine), you can do away with the constants and just specify the strings.

Step 1A: Async Action Creators

I have another action creator – the one that initiates the request. That one was a problem. To be honest, I don’t think Redux actually deals with async well. It should “just work” and it doesn’t. Here is my function:

import fetch from 'isomorphic-fetch';

// baseUrl is required for the fetch actions
let baseUrl = '';
if (window.GRUMPYWIZARDS &amp;&amp; window.GRUMPYWIZARDS.base)
    baseUrl = window.GRUMPYWIZARDS.base.replace(/\/$/, '');

/**
 * Redux Action Creator for requesting authentication information
 * @returns {Function}
 */
export function requestAuthInfo() {
    return (dispatch) =&gt; {
        let fetchOptions = {
            method: 'GET',
            credentials: 'include',
            cache: 'no-cache',
            mode: 'cors'
        };
        return fetch(`${baseUrl}/.auth/me`, fetchOptions)
        .then((response) =&gt; {
            if (!response.ok &amp;&amp; response.status !== 401)
                throw new Error(`Invalid Response from ${baseUrl}/.auth/me:`, response);
            if (response.status === 401)
                return new Promise((resolve) =&gt; { resolve(false); });
            return response.json();
        })
        .then((response) =&gt; {
            if (!response)
                dispatch(receiveAnonymousAuth());
            else
                dispatch(receiveAuthenticatedAuth(response));
        })
        .catch((error) =&gt; {
            dispatch(receiveErrorCondition(error));
        });
    };
}

There is a little code at the top to figure out where the API actually is. The majority of the code is a direct copy from my original store implementation. Instead of doing the store update right there, I dispatch another action (created by one of the action creators I wrote earlier) to handle the actual action.

Step 2: Reducers

The next element in the Redux implementation is a reducer. A reducer takes a state and an action and turns it into the new state. This is a relatively simple concept. The “reducer” terminology is from the Array.reduce() functionality within JavaScript, which is designed to provide an accumulator functionality – you start with an initial value and mutate it based on each value within the array. In the case of Redux, you start with the current state of the store and you mutate it based on the action. Except that you don’t mutate the state – you return a new copy of the state. So, I guess the analogy breaks down there.

One of the golden rules of Redux is this: Reducers must be free of side effects.

In other words, if you call the reducer with the same state and the same action, it will return the same state each time. You can’t put “call this other API” or “look in a database” or that sort of thing. Right now, I’ve got one reducer (called reducers.js) that has a case statement in it to handle each action.

/* eslint-disable no-case-declarations */

const initialState = {
    phase: 'pending',
    user: null,
    error: null
};

export default function authReducer(state, action) {
    if (typeof state === 'undefined') {
        state = initialState;
    }

    switch (action.type) {
        case 'AUTH-ANONYMOUS':
            return Object.assign({}, state, {
                phase: 'anonymous',
                user: null,
                error: null
            });

        case 'AUTH-AUTHENTICATED':
            let claims = action.providerInfo.reduce((target, claim) =&gt; {
                target[claim.typ] = claim.val;
                if (claim.typ.indexOf('http://schemas.xmlsoap.org/ws') !== -1)
                    target[claim.typ.slice(claim.typ.lastIndexOf('/') + 1)] = claim.val;
                return claims;
            });

            let user = {
                accessToken: action.providerInfo.access_token,
                claims: claims,
                firstname: claims.firstname || '',
                id: action.providerInfo.user_id,
                provider: action.providerInfo.provider_name,
                providerToken: action.providerInfo.authentication_token,
                surname: claims.surname || ''
            };

            return Object.assign({}, state, {
                phase: 'authenticated',
                user: user,
                error: null
            });

        case 'AUTH-ERROR':
            return Object.assign({}, state, {
                phase: 'error',
                user: null,
                error: action.error.message
            });

        default:
            return state;
    }
}

UPDATE Dan Abramov contacted me and suggested that putting the initialState with the reducer was “the right pattern”. We don’t want to be propagating anti-patterns. As a result, I have moved the initialState to the reducer after the initial publication of this blog post. You can also use an ES6 default argument to set the initialState.

Why is this requirement for no side effects so important? You do like to test your code, right? This requirement enables the testability of the code, and that is very important.

There are definitely other ways to organize your code once your store (and state requirements) grow, and you can read about them over on the Redux web site. However, this is good enough for now. We’ve got an action creator, a set of actions that describe the manipulations to application state we want to handle, including one action that won’t actually work (we’ll get onto that later, but take a wild guess as to which one!) and a reducer that will return the new state when it is fed an action.

Step 3: Creating the Store

The next question, of course, is how do we tie all this together? Well, that’s the job of the store. Note that this is a singular entity. In my implementation of flux, I would suggest that you have different stores to handle different types of data. If you are doing a blog, you might have a store for authentication, a store for blogs, a store for comments, and so on. In Redux, there is only one store.

Here is how I implemented the store given the reducers and actions I’ve already created:

import { createStore } from 'redux';
import reducer from './reducers';

let store = createStore(reducer);

export default store;

The store is created with createStore(). The first argument is the reducer (or set of reducers if your application is more complex).

UPDATE: createStore() takes a second optional argument – the initialState. However, Dan Abramov contacted me and suggested that this was an anti-pattern in client applications. I’ve since moved the initialState to the reducer (above).

You can now use this store to subscribe to store changes and to dispatch actions. Dispatching actions that are not asynchronous is easy:

// store.dispatch(actionCreator(args));
// For example:
store.dispatch(receiveAuthenticatedAuth(response));

You’ve actually already seen this in the actions.js file I showed earlier. However, that async method is going to take something. Here is how I started with it:

import { createStore } from 'redux';
import { requestAuthInfo } from './actions';
import reducer from './reducers';

const initialState = {
    phase: 'pending',
    user: null,
    error: null
};

let store = createStore(reducer, initialState);

// Dispatch the initial action
let requestAction = requestAuthInfo();
requestAction(store.dispatch);

export default store;

It doesn’t actually dispatch an action. I’ve got a problem with that, but I’ll come back to that later. On to our components:

Step 4: Update the Component Views

I’ve got one component view – the Chrome.jsx file. There are also a couple of calls you need to know – the main one being that you can subscribe to changes and then unsubscribe later on. Let’s take a look at my Chrome.jsx – at least the important parts. First off, the constructor:

    constructor(props) {
        super(props);
        logger.entry('$constructor', props);
        this.state = {
            phase: 'pending',
            user: null,
            error: null,
            leftMenu: {
                isOpen: false
            }
        };
        logger.debug('state = ', this.state);
        logger.exit('$constructor');
    }

Note that the state includes all my store variables. This actually is fairly important at this point. It will become less so later on. Now, onto the component state lifecyle functions:

    /**
     * React API: Called when the component is mounting itself in the DOM
     *
     * @returns {void}
     * @overrides React.Component#componentWillMount
     */
    componentWillMount() {
        logger.entry('componentWillMount');
        this.unsubscribe = store.subscribe(() =&gt; { return this.updateState(); });
        logger.exit('componentWillMount');
    }

    /**
     * React API: Called when the component is removed from the DOM
     *
     * @returns {void}
     * @overrides React.Component#componentWillUnmount
     */
    componentWillUnmount() {
        logger.entry('componentWillUnmount');
        this.unsubscribe();
        logger.exit('componentWillUnmount');
    }

    /**
     * Update the internal state of the component-view from the flux store
     */
    updateState() {
        logger.entry('updateState');
        this.setState(store.getState());
        logger.debug('New State = ', this.state);
        logger.exit('updateState');
    }

This is pretty much standard stuff for flux. You register your interest in the componentWillMount() method and then deregister in the componentWillUnmount() method. In the updateState() method, I merge the stores state with the components state which will then re-render the DOM.

That’s pretty much all there is to redux. Instead of a complicated function in a store, the store is completely separated and reducers take over the task of actually doing the state transitions. Otherwise, this is as vanilla Redux as you can get. Sure, it’s a little more modular, and smaller (141 lines of code instead of 214 for my store implementation), but…

The only real advantage is that I’m not writing the store myself.

However, there is much more to Redux than what we’ve done thus far. In the next post, I’m going to take a look at two of those things. Firstly, I am going to simplify my component view to get rid of a lot of the boiler-plate code for handling state updates. Secondly, I’m going to look at the role of middleware to handle async functions. Until then, check out the code in my GitHub Repository.

Styling React Components with Radium

Anyone who is a long time reader of my blog knows I hate CSS. That’s why I am always on the lookout for something that makes it easy for me. I’ll add another wrinkle to the puzzle – I just started using Material-UI for some React components – it allows me to expend the effort on the truly important pieces of my application without worrying about a design language. I just use Googles Material Design language.

The question always on my mind is “am I doing this the right way?” Or am I merely doing it some way that works and I’ll find out this is the wrong way later on. I’ve got a pretty good stylesheet system at this point. Why would I change?

Well, for that library of components that someone else produced is one great reason. They require a style property to be added to add custom styling. Alternatively, I can add the !important tag all over the place – something that is ugly and limits the choices I make for styling. I don’t like !important – it is the left refuge in CSS.

Enter Radium – a library that still forces me to use CSS, but allows me to style components with JavaScript instead of SCSS. Here is how I converted my project to use Radium.

Step 1: Remove the style loaders from Webpack

I’ve got the following code in my webpack.config.js for handling stylesheets:

    module: {
        loaders: [
            // JavaScript and React JSX Files
            { test: /\.jsx?$/, loader: 'babel', exclude: /node_modules/ },
            { test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/ },

            // Stylesheets
            { test: /\.css$/, loader: 'style!css?sourceMap|postcss' },
            { test: /\.scss$/, loader: 'style!css?sourceMap!postcss!sass?sourceMap' },
            { test: /\.scss$/, loader: 'stylelint' }
        ]
    },

I don’t need these any more as I am converting things over to JavaScript. I can delete the highlighted lines. In addition, there are a whole bunch of configuration elements within the webpack.config.js that I no longer need because I am not processing SASS files – those can go as well. This makes my config much leaner.

Incidentally, I also removed the externals for React and ReactDOM. This is because of a bug in Material-UI that causes errors (and malfunctioning button animations) if you include the externals. If you want to watch the bug, it’s in GitHub Issues. Unfortunately, that increases the size of my JavaScript significantly. I’m taking that temporary hit to speed development.

Step 2: Move imports to the HTML file

I have the Roboto font (and potentially other fonts) included as a @import statement in my CSS. I need to convert them to links instead. So, this:

// Roboto Font
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700');

Becomes this in the index.html:

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Grumpy Wizards</title>
    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700">
</head>

Fortunately, I only have a couple of these, but it’s an important factor. Similarly, if you have any font definitions using @font-face, then they need to be converted to regular CSS files and loaded manually within your HTML file.

Step 3: Convert your mixins to JavaScript

I have a couple of files that have variables to hold the colors and fonts. I want to continue to use those variables, so I need to convert them to Javascript. Here is the old _colors.scss file:

$color-1: #009688;
$color-2: #A7FFEB;
$color-3: #FF5722;
$color-4: #311B92;
$color-5: #004D40;

$color-trans-1: rgba(255, 255, 255, .1);
$color-trans-2: rgba(255, 255, 255, .2);
$color-trans-3: rgba(255, 255, 255, .3);
$color-trans-4: rgba(255, 255, 255, .4);
$color-trans-5: rgba(255, 255, 255, .5);
$color-trans-6: rgba(255, 255, 255, .6);
$color-trans-7: rgba(255, 255, 255, .7);
$color-trans-8: rgba(255, 255, 255, .8);
$color-trans-9: rgba(255, 255, 255, .9);

And here is the new appStyle.js file:

let appSettings = {
    color1: '#009688',
    color2: '#A7FFEB',
    color3: '#FF5722',
    color4: '#311B92',
    color5: '#004D40',
    
    trans1: 'rgba(255, 255, 255, .1)',
    trans2: 'rgba(255, 255, 255, .2)',
    trans3: 'rgba(255, 255, 255, .3)',
    trans4: 'rgba(255, 255, 255, .4)',
    trans5: 'rgba(255, 255, 255, .5)',
    trans6: 'rgba(255, 255, 255, .6)',
    trans7: 'rgba(255, 255, 255, .7)',
    trans8: 'rgba(255, 255, 255, .8)',
    trans9: 'rgba(255, 255, 255, .9)',

    fonts: {
        sans: "'Roboto','Segoe UI',Frutiger,'Helvetica Neue',Arial,sans-serif"
    }
};

export default appSettings;

This has all my variables in one place now and in JavaScript. There isn’t much actual difference between the two files.

Step 4: Style your initial application

Normally, you would attach Radium to your components. Unfortunately, you can’t do that initially – there is no component to which you can attach. You are rendering existing components. For those cases, you can use the following:

import { StyleRoot } from 'radium';
// ... and the rest of your includes ...

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

// render the page
ReactDOM.render(
    <StyleRoot style={pageStyle}>
        <Router history={browserHistory}>
            <Route path="/" component={Chrome}>
            </Route>
        </Router>
    </StyleRoot>,
    document.getElementById('jsx-page')
);

Note that my old code just had the Router component in it. The new code wraps the old code within a StyleRoot. That has a style attribute to set the style on it. Inevitably, this is a minimal stylesheet because you have your chrome component all set up to do the work of rendering the UI.

Step 5: Update your components for Radium support

Let’s take a look at my Chrome.jsx before adjustment – at least the important pieces of the top of the file:

import React from 'react';
import AppBar from 'material-ui/lib/app-bar';
import LeftNav from 'material-ui/lib/left-nav';

require('./Chrome.scss');

/**
 * Provides all the chrome around the application
 * @extends React.Component
 */
export default class Chrome extends React.Component {

And now the new code:

import Radium from 'radium';
import React from 'react';
import AppBar from 'material-ui/lib/app-bar';
import LeftNav from 'material-ui/lib/left-nav';

/**
 * Provides all the chrome around the application
 * @extends React.Component
 */
@Radium
export default class Chrome extends React.Component {

This is something new for me – ES7 decorators. Decorators can do all sorts of wonderful things. At their core, the change the value of the class at design time – before instantiation. This means you can wrap the class in something else – in this case, the style processor that Radium brings to the table.

You will quickly discover that this won’t work on its own. Babel with the ES2015 and React plugins does not support ES7 decorators. Fortunately, there is a plugin for that:

npm install --save-dev babel-plugin-syntax-decorators

If you haven’t already done so, this is a great time to install radium as well. Don’t forget to also add syntax-decorators to your .babelrc file:

{
    "presets": [ "es2015", "react" ],
    "plugins": [
        "transform-class-properties",
        "syntax-decorators"
    ]
}

You should be able to build the project now – for the first time in a while.

Step 6: Add Style to your components

I was creating an SCSS file for each component in my prior method. Now I need to convert the stylesheet to JavaScript. Here is the Chrome.scss file that I am going to convert:

@import 'colors';
@import 'fonts';

.chrome {
    display: flex;
    flex-flow: column nowrap;
    height: 100%;
    width: 100%;

    &--content {
        flex-grow: 1;
    }

    > footer {
        background-color: $color-5;
        display: block;
        text-align: center;

        > h6 {
            color: $color-trans-8;
            font: 0.8rem $sans-fontstack;
            margin: 0.5rem 0;
        }
    }
}

It wasn’t that big. In addition, I want to take care of the styling for my app bar, so I’ll do that at the same time. With apologies for the long listing, I’ve included the new render() method:

    render() {
        logger.entry('render');

        // Define Event Handlers
        let onMenuIconTap = (event) => { return this.onLeftNavDisplay(event, !this.state.leftNavIsOpen); };
        let onRequestChange = (open) => { return this.onLeftNavDisplay(null, open); };

        // Components
        let leftNav = (
            <LeftNav docked={false} onRequestChange={onRequestChange} open={this.state.leftNavIsOpen}>
            </LeftNav>
        );

        // Style
        let styles = {
            chrome: {
                display: 'flex',
                flexFlow: 'column nowrap',
                height: '100%',
                width: '100%'
            },
            appbar: {
                backgroundColor: appStyle.color1
            },
            footer: {
                backgroundColor: appStyle.color5,
                display: 'block',
                textAlign: 'center'
            },
            footertext: {
                color: appStyle.trans8,
                font: `0.8rem ${appStyle.fonts.sans}`,
                margin: '0.5rem 0'
            }
        };

        let jsx = (
            <div style={styles.chrome}>
                <header>
                    <AppBar style={styles.appbar} onLeftIconButtonTouchTap={onMenuIconTap} title={'Grumpy Wizards'}/>
                    {leftNav}
                </header>
                <section style={{ flexGrow: 1 }}>
                    {this.props.children}
                </section>
                <footer style={styles.footer}>
                    <h6 style={styles.footertext}>{'Copyright \u00a9 2016 Adrian Hall'}</h6>
                </footer>
            </div>

        );

        return logger.exit('render', jsx);
    }

The first block is my stylesheet – converted into a JavaScript object. This means I can represent that object any way I want – as long as it resolves to an object. For example, I might use Object.assign to merge styles together, store it in a library and import the styles, do calculations, call functions, or anything else I want to do. The style properties need to be converted to camelCase – instead of flex-flow, use flexFlow.

The second part is in the JSX. I attach a style attribute where I need to add style. Since I’ve created a stylesheet as a set of nested objects, they can get referenced using the standard Javascript object dot notation. Note that I don’t have to use the object notation – simple things, like the flex-grow style property at line 106, can just be included.

Wrap Up

There are some things that are different than just using the style attribute in your HTML code though. Normally, attributes like ‘:hover’ and media queries are not available within the style attribute – that is reserved for the CSS stylesheet. You can specify both browser states like :hover and media queries using Radium, so that limitation of the style attribute does not exist.

There is a lot to recommend this style mechanism. My components are now self-contained – no extra files. I’m just using pure JavaScript. That means, for example, I can distribute components with styling already built in. I don’t need to wonder if they are using webpack or browserify and what format I need to present the stylesheet. Sure, the designers in your life are likely to hate it, but I find the code cleaner. I’m really enjoying the discovery of Radium.

Oh – and don’t forget to remove all the loaders and linters dealing with style from your package.json! My code, as always, is in my GitHub Repository.