• Jeroen Savat

  • Frontend Software Engineer

  • Andy Somers

  • Software Engineer

You may have heard about the React library before. It is usually mentioned in the same breath as Angular2 or, in this case, Redux. Though you can use Angular2, or any other libraries such as Vue and Polymer, we have been using React in combination with Redux and have found it to be a very potent combination. In this post we'll explore why React and Redux work so well together.

React

In a Java or .NET web application, your pages are typically rendered completely in HTML. Your JavaScript code hooks on events and the DOM and, if you want to reuse code, you have to make sure the HTML elements are being rendered everywhere you might need them.

A solution would be Thymeleaf fragments, JSP tags or Partial Views in Razor. But even then there is a big disconnect between your HTML and your JavaScript code, because you can never be sure you incorporated the right JavaScript code files with the correct output.

As you may know, web components are well on their way to be natively supported by most popular browsers. These components mark a shift towards a higher cohesion in front-end. In the JS library React, a single component is responsible for both presentation logic as well as the rendering of HTML elements.

The first experience we had with the component-based library React was at Devoxx 2016, where we used it to render a simple list of test results on a live scoreboard. React is powerful (with relatively little code you can achieve a lot) and it is relatively easy to comprehend. More specifically, you can gently introduce it into existing web apps, at least, that’s how we started incorporating it into our much bigger projects.

class User extends React.Component {
    computeIndexClassName() {
        let cls = “”;
        if (this.props.index % 2 === 0) {
            cls = “even”;
        }
        return cls;
    }
 
    render() {
        return (
            <div className="row">
                <div className={this.computeIndexClassName()}>
                    {this.props.index}.
                </div>
                <div className="data name">
                    {this.props.user.firstName}
                    {this.props.user.lastName}
                </div>
            <div className="data amount">{this.props.user.time} ms
                </div>
            </div>
        )
    }
}

The piece of code above is a simple React component that is responsible to render user data. It is called by another component that loops over a list of users.

The receiving component gets its properties (accessible by this.props) from the calling component. Every time the receiving component is rendered, the computeIndexClassName method gets called to add an extra class name to the index div if the index is even.

Note that here we are also using JSX templating, which “provides syntactic sugar for the "React.createElement"-function”, to easily render HTML (source: JSX In Depth).

In the same way that the React library helps us to mentally map our application into components, Redux allows us to map how changes to our application can happen structurally.

Redux

It’s important to realize that the codebase of Redux is, in essence, very small. The entire framework is about 100 effective lines of code. Actually, Redux is more about patterns than it is about using its API (in that regard the code is just a “helper”). Where in vanilla Javascript you are responsible for structuring presentation logic, Redux can offer the infrastructure for handling state.

It’s also worth noting that Redux has abundant documentation and there exists a great devtools-plugin for debugging and developing. Dan Abramov, the creator of Redux, has also published 30 free video lessons covering all concepts of Redux - a recommended watch.

A Redux application has a state tree that contains structured data about the state of the application, as you can see in the graphic. The way in which you structure these data is entirely up to you (by design, Redux imposes very little), but the end result will always be a store in the form of a JSON object.

The Redux Principle

As you can see in the graphic, any component can modify this store - and Redux will notify any other component that has subscribed to changes. Let’s briefly explore how this works in practice.

The way in which a component can modify the state is by dispatching actions:

const ADD_TODO = 'ADD_TODO'
const add_todo = {
  type: ADD_TODO,
  text: 'Build my first Redux app'
}
store.dispatch(add_todo);

An action is a structured object containing an action type (i.e. what just happened) and optionally some data (i.e. what needs to change).

When dispatching an action, Redux will run the action through a reducer. This is where Redux gets its name from. A reducer is a pure function that takes an input, in this case the action type and optional data (text), and outputs a changed state. This new state replaces the previous state.

The code below is what a reducer function looks like (note that one reducer can handle multiple actions):

function todoApp(state = initialState, action) {
  switch (action.type) {
    case SET_VISIBILITY_FILTER:
      return Object.assign({}, state, {
        visibilityFilter: action.filter
      })
    default:
      return state
  }
}

A nice side effect of this approach is that any single state in time becomes the result of a list of applied actions, making it possible to easily undo or redo any action that happened in the past.

This can come in handy in the development process during which you might want to retrace your steps in the applications, repeat certain actions or restore a certain state. In a traditional approach, there is no concept of applied actions history, making such a functionality non-trivial and, probably, hard to achieve.

If a component wants to get notified about changes in the tree, it can subscribe to the store. Any time an action is dispatched, subscribed components will be notified of what the new state is and they can respond, if and when needed.

store.subscribe(function() {
  console.log(' something changed, this is the new state:',
                store.getState()
            );
}

By following these simple patterns, state in your application becomes predictable. Understanding the flow of state becomes much easier. Redux manages complexity and improves ease of maintenance. Learning Redux is not that hard. It just might take a bit of practice to fully grasp all the concepts.

But why is it that React and Redux go so well together? More specifically, how is this combination of code better than the usual?

The React/Redux Plugin

While you can use Redux without React, the React/Redux plugin makes for a seamless integration with React (as you can see in the official React bindings for Redux). By using this plugin, components can automatically update themselves whenever state changes, and dispatching actions becomes trivial.

Vice versa, it’s also important to realise that you can also use React without Redux; for an application that has very little client-side state, Redux is overkill since you might get away with just using React setState (which is built-in and has no set-up time or boilerplate as opposed to Redux).

All in all, the React/Redux approach makes it easier to reason about your code, which makes your code more maintainable. Moreover, you can use the official React/Redux bindings already laid out for you. When combined, the React and Redux combo just feels logical.

Up until now, a part of the front end logic, HTML for instance, was rendered by the back end. Like when a Java web app uses JSPs or Thymeleaf to output HTML. However, an ideal situation would be a complete separation of concerns between front and back end. Such an approach enables API first development and promotes loose coupling between both ends. The React/Redux combo encourages this view and seems to close the gap here. With this combination, most of your front end logic is now actually living on front end.

 

Of course, there are plenty of other reasons why this combination works so well, like the fact that React and Redux are clearly documented and that they have a well-established community, but the ones mentioned above are the most important ones when it comes to managing complex software.

But what do you think? Any other important reasons we forgot to mention? Or is there another combination that works better for you? We’d like to hear what you think of it. Let us know in the comments below.

Related Articles