Notes from my first React + Redux project

React is one of the hottest JS frameworks out there and I want to share my first experience with you.

Alex Escalante
Audelabs
15 min readJan 26, 2017

--

Everybody is talking these days about Javascript frameworks. There are a lot of them, and there’s also such amount of articles, infographics, bullet lists and whatnot that some people are starting to feel overloaded and just prefer to stick with the good old jQuery or even go the way of pure Javascript and roll everything up by themselves.

While I agree that some projects (particularly small ones, proofs of concept or even some Minimum Viable Products (or MVP) could get away with a simplistic solution, a real world production system often demands much more and there is no point on reinventing the wheel and do everything by hand. Specially when there are awesome, minimal frameworks that are elegant and well written.

Of course you will get into complications but, don’t we all do, no matter our choices? Cheer up and keep learning is what I say…

This is how the final UI looks like. Not all options are enabled, but you get the idea…

Welcome to my MVP

Last May I was invited to join a small team of senior programmers in a project to create an online payment processor using a number of cutting edge technologies for a major player in the payment gateway business in Latin America.

We implemented a highly scalable micro service architecture to process thousands of requests per minute and I was in charge of the front end: a small, easy to integrate app for every merchant software. When the shopper clicks the checkout button, a modal window will come up showing available payment options and gathering the necessary information to generate every request for our backend.

Our final delivery included a quick integration with Prestashop (which I didn’t code, by the way, because integration was supposed to be easy, remember?)

My most important requirements were a bit stringent:

  • Our UI should run in any desktop or mobile browser. Latin American users are not used to updating software very often so, even if “any” is such a strong word, this means we have to go down to Windows XP and IE 9.
  • Load times should be kept to a minimum. Slow connections are always a source of trouble in this market, so we should keep our bundle size to a minimum.
  • We should do it right. Saying that you are building a “minimum viable product” doesn’t mean you can get away with cheap code put up together haphazardly with some sort of script. We could cut out features but we should deliver enterprise ready code in a predictable way.
  • We should do it fast. We were given three months initially. For the whole solution, not just the UI. Sounds a bit crazy and of course our project slipped behind schedule. But we also did a lot more of what was expected, so everybody was sort of satisfied.

Why did I chose React and Redux?

React is very small, relatively simple and fast rendering view library that you use to build your UI components. It supports component state and a number of other features but it doesn’t give you all you could need to build a full app, like other frameworks, particularly Angular, do. This means that you get to pick and chose what you really need instead of carrying a lot of baggage from the beginning.

Redux manages all the state in the application, this means that your data is not scattered around components. Your components can still have internal state used only for rendering, like whether a menu is visible or not, but the really important stuff is kept in a single location and it gets updated only by your reducers. When state gets updated, Redux notifies and the components redraw themselves according to the new state. See below for more information and examples.

Sketching and prototyping

Coding the solution is sometimes the easiest part of the project. Knowing what you need to code is another story. For this project, it turned out that even when I was using a recently learned set of tools and libraries, my biggest challenge was getting all the stakeholders in the same page regarding the features and the look & feel of the UI. Some of them were confused with the fact that the UI was expected to behave nicely on mobile devices but this was an HTML5/CSS3 solution, not a native one. In the end I was able to deliver a satisfactory experience in most of the devices, but I don’t think that you can currently get a top notch UI on every platform using a single code base.

Considering the very limited screen area of mobile devices, my initial proposal was very minimalistic. I tried to keep UI elements to a minimum to focus the user on their immediate choices. However, my take was dismissed right away because my clients wanted to bring some of the characteristics of the former solution into the new one. It took a lot of iterations to come up with a final design.

It’s been a while since I adopted Sketch for doing UI design, and the industry seems to agree with me on the point that there are not many better choices for this. The symbol feature of Sketch is a particularly helpful one, and it allowed me to refactor my design very quickly and effectively.

I was asked to provide a functional prototype for the last iteration. Our stakeholders wanted to see how our search field filtered out the list of possible payment places. For this, I decided to try Framer, which is different from other prototyping tools because you actually have to write code instead of dragging & dropping UI elements like most tools want you to do these days. This of course takes Framer to a whole new level at the exchange of some complexity.

While it’s a nice tool, and the end results can look quite formidable, I think I could have skipped Framer for this particular project because my needs where rather simple and it would have been faster to just go ahead and start writing HTML and Javascript. I think Framer is of most value when prototyping complex, native UI interactions, and I have to say that even if I understand they wanted to somehow be “designer friendly”, I was put off by their choice of Coffeescript for their scripting language. Now that the Framer team is considering dropping it in favor of regular Javascript, many people like me should be happier.

Setting up the project

There are many ways to start a React project, but I would advise you not to start from the ground using npm to get all your libraries together. It would be time consuming and error prone. Today you could probably choose Create React App, which is a very nice project starter backed by the very same people who makes React. For this project, however, I went for React Slingshot. It creates a very complete setup that brings together several tools that will make your development easy and enjoyable:

  • Babel. Support for modern features of the Javascript language, also called EcmaScript 6 or ES6, for short, is not uniformly present in all browsers. If you want to use it —and believe me: you do, then you definitely need a transpiler. This tool will take modern code and output code that will run in just about any browser. Now you can code using your favorite language constructs: arrow functions, destructuring, rest/spread, async functions and much more. Babel also supports React’s JSX, which is the XML syntax used to declare how your components look and it’s just syntactic sugar over function composition:
// This looks like HTML but it's actually in a Javascript source 
// file. Look at the variable declaration:
var profile = <div>
<img src="avatar.png" className="profile" />
<h3>{[user.firstName, user.lastName].join(' ')}</h3>
</div>;
// Now, look at the syntax transformation output by Babel:var profile = React.createElement("div", null,
React.createElement("img", { src: "avatar.png", className: "profile" }),
React.createElement("h3", null, [user.firstName, user.lastName].join(" "))
);
  • Redux. This is one of the newest proposals from the functional programming trenches: a predictable state container for JavaScript apps. With this library, the state of your app is modeled as a tree and is managed in a central place. You get to modify it in a very orderly way by posting actions that are processed by reducers, which are actually just pure functions. Take a look at this overly simplified code from the official repository:
// this is a reducer
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}

// Create a Redux store holding the state of your app.
// Its API is { subscribe, dispatch, getState }.
let store = createStore(counter)
// The only way to mutate the internal state is to dispatch an action.
// The actions can be serialized, logged or stored and later replayed.
store.dispatch({ type: 'INCREMENT' })
// 1
store.dispatch({ type: 'INCREMENT' })
// 2
store.dispatch({ type: 'DECREMENT' })
// 1
  • SASS/PostCSS. I don’t do regular CSS anymore. SASS is to CSS what Babel is to Javascript: it provides a lot of nice constructs that will help you write better code. PostCSS is an extensible framework that gives you even more capabilities, like vendor prefixes.
  • ESLint. This tool will help you produce quality code by checking every source file against your preferred set of rules to make sure you follow good coding standards. And it’s very configurable.

There are more interesting tools that come bundled, but I think I will move forward for something quite interesting…

The build system

Before this project my build system was implemented in a Gulp script. Gulp is similar to other tools in the sense that you write a number of tasks and chain them all together to construct your software. It’s pretty imperative, and depending on the steps you need to construct your deliverables, sometimes the script can grow unwieldy. In fact, build systems are typically a source of fear and trouble, particularly with large setups. Yes: I do remember the Java systems I worked with in the 2000's!

Enter Webpack. It’s said to be a “module bundler” which “takes modules with dependencies and emits static assets representing those modules”, but I’m sure you will feel this description falls short. Let’s say, in the first place, that Webpack’s approach to building your output assets is more declarative than that of Gulp and other tools. You won’t be writing much ad-hoc scripts to handle the specifics of your project because Webpack has a lot of features and it’s super configurable. Granted: it’s also a bit complex, but once you get around the documentation, you’ll be fine. Let’s see some of the things Webpack can do for you:

  • It understands the latest Javascript: just use import in your main file and all your dependencies will be pulled into your bundle automatically.
  • It can also “import” images, icons and other stuff. Sounds a bit crazy, but it works very well.
  • It supports code splitting. This is big because you can keep your main bundle minimal and load additional code dynamically whenever you need it. You will have your users happy with small load times! How do you use it? Well, just use System.import to pull extra modules and it all happens automatically, again. As you can appreciate, you can right away handle the case where your module failed to load
function onClick() {
System.import("./module").then(module => {
module.default;
}).catch(err => {
console.log("Chunk loading failed");
});
}
  • It supports Hot Module Replacement (HMR). This is great when you’re developing because your modified code get’s reloaded automatically ( at least in most cases). You don’t have to restart your system to see your changes. And with React Slingshot, this came configured as well. It just worked.

I’m just barely picking some nice features that I know you will be glad to hear about, but there is a lot more to Webpack. I recommed you give it a try when your next Javascript project arrives.

I want to see some code now!

Now that we have our project setup and a nice build system, we can start coding. Since I’m not allowed to show any actual code I wrote for my client because of the terms of our contract, I will write demonstrative snippets right here to show you what I’m talking about.

A typical React system starts with a humble HTML file that loads your main bundle and sets up the area your main component will use to display itself:

<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="UTF-8">
<title>This is just an example</title>
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>

Take a look at the div with with the app id, and then look at the main Javascript file:

import React from 'react';
import {render} from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './store/configureStore';
const store = configureStore();render(<Provider store={store}><App/></Provider>, document.getElementById('app'));

That render() call there will instantiate your main component and insert it right where you asked. That’s all you need to bootstrap your React + Redux app. The configureSore file there may look just like this:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers';
export default function configureStore(initialState) {
return createStore(
rootReducer, initialState, applyMiddleware(thunk)
);
}

Your Redux store gets setup with your main reducer, which actually can be a composite that allows you to split your actual reducers, and there can be many of them as you can see from this example:

import { combineReducers } from 'redux'
import todos from './todos'
import counter from './counter'
import someOtherReducer from './someOtherReducer'
export default combineReducers({
todos,
counter,
someOtherReducer
});

What does a React component look like?

Well, you already saw some of the typical React code:

render(<Provider store={store}><App/></Provider>, document.getElementById('app'));

There you can appreciate the typical syntax of HTML inside of a JS call: Provider is the component that composes over your main App component, giving it access to the Redux setup. A component written using the ES6 class syntax might look as simple as this:

class App extends React.Component {
render() {
return (
<div className="app">
<h1>Welcome to {this.props.name}</h1>
</div>
);
}
}

When your component gets instantiated, it gets supplied with a number of properties, and you get access to them using the this.props object.

If your component doesn’t need to keep state (thats what Redux is for, in the first place) or do anything fancy, you can even skip using classes and write a stateless functional component:

render(props) {
return (
<div className="app">
<h1>Welcome to {props.name}</h1>
</div>
);
}

As you can see, a component like this is just a function which takes its properties as an argument and then return the same JSX code that you would have returned from a render() method.

This article only scratches the surface of React, so we need to move forward and, hopefully, leave you wanting to learn more, so…

Talking to the server

If you read the code carefully, you will notice a reference to a module called redux-thunk.The point for this is interesting: typically, your Redux actions are passed as simple functions to your React components, and they get called, or dispatched, as a result from a user interaction, the push of a button or something, and then your reducer updates the state of your app and signals react of the new state so your components can update themselves to reflect it.

But what happens when you need an action dispatched in some other occasion, how do you request data from a server, for instance, and how do you process it when it arrives? Well, Redux supports a feature called middleware: third-party extension points between dispatching an action, and the moment it reaches the reducer.

There are a number of middlewares out there, doing different things. Particularly, Redux Thunk gives your actions additional powers. Instead of just saying which action to execute and with which parameters, they get to keep a reference to the dispatcher object around, so they can asynchronously dispatch subsequent actions when they need it.

Want to see an example? This is a fictional action that just requests sales data from a specific region of the country:

export function requestSalesData(region) {
return { type: types.REQUEST_SALES_DATA, region };
}

Ok… your UI can now request the data: your reducer will get this object you return stating your intention and even the region you’re interested in and… what? Reducers should not handle communication to and from the server, they just get the data and apply it to the current application state to produce the next, fresh state.

Where and how do you handle the actual download from the server? With Redux Thunk, your action can return a function instead of a simple object, so, we can now write an action that looks like this:

export function requestSalesData(region) {
return (dispatch) => {
return fetch(`https://yourserver.com/sales/${region}`), {
method: 'GET',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token // JSON Web Token! :)
})
.then(response => response.json())
.then(json => dispatch(updatePaymentReceivers(json)));
}
}

Now we can return a function instead of a simple object. And since this function receives the dispatcher, we can hold it around until we get the actual data! Just pay attention to the last then call.

I’m using Fetch to talk to the server because it’s nice and easy and someday it will be present on all browsers. I use what we call a polyfill to provide it when the browser doesn’t. As you can see, Fetch supports promises, which simplify asynchronous calls. You just wait for the data to arrive and then()process it.

In the third line you get an example of the ES6 string interpolation syntax for getting the requested region into the URL string.

Do you want to know more about this project?

This article barely covers the UI, but we used a number of cool new technologies like C++ 11, Docker and Kubernetes. If you want to read more, there are a couple more articles written by our expert C++ team member:

Testing

I usually write my unit tests before writing the components I am going to test. When I need a component to have additional capabilities, I write the tests first to check for them. With the tests failing, I modify the component to have the desired features until tests go green. This discipline is called TDD or Test Driven Development and has saved me from a lot of trouble. Even if it doesn’t feel natural for you at first, I recommend to stick to it.

When you have dozens of small unit tests checking everything is going well, and you write more tests when you find a bug to be sure it doesn’t return, you will feel safe about changing your code in whichever way you like. And this is a blessing! Just try to do a big refactoring without a test suite, you will know what I mean…

For this project I used Mocha with Chai. It’s a pretty neat combination, expressive and powerful. I ran into minor problems when testing promises, and then with some false positives… I did sort out everything in the end and was very pleased.

Another kind of tests that are very important, specially when your code needs to be tested on just about any platform, are the automated functional tests. For this I wrote a test suite using Selenium and Webdriver.io, and we payed for the services of Browserstack to run our tests in every operating system and browser combination we needed. I found and eliminated bugs that were only present on some combinations and not others, I would just run all my tests automatically whenever I made relevant changes and check everything was ok… It was awesome.

Final words

This an MVP so there are a number of improvements I would put in place sooner or later. The use of React Thunk for instance, while simple, puts a lot of logic where is not always convenient. There is another, very appealing middleware, called Redux Saga, which I think provides a superior model. With it you can keep your actions and reducers simple, and you have special components, called sagas, that get activated when some actions are dispatched, being able to carry out backend operations and other stuff, posting subsequent actions themselves. Neat.

Would I use React again? Certainly. I even will try React Native very soon. This doesn’t mean I am not interested in any other framework, but I think that React is ahead of others, particularly bigger, more complex ones like Angular. I tried Angular 1 and disliked it. Angular 2 seems better but still, I think that other less traditional approaches for doing client side are superior. Just check what people is doing with Vue.js or Inferno.

There are several options to Redux as well, other state containers that people are using with joy. Check MobX if you feel Redux is a bit too much for you. And if you have a complex queries against your backend, definitely check Relay and GraphQL.

You have probably gathered that the React + Redux combo is a departure from the traditional MVC/MVVM/whatever architectures well into the functional/immutable domain. I welcome this gladly. I think we needed it but, what do you think?

Did you like what you read? Do you have any questions? We are a small, dedicated team of senior programmers. We can help you build your next successful product. For more information, please visit our website

--

--