Front-End Insights

Redux – the best Flux implementation

ProgrammingReactRedux

One of the key features of React components is the state built into them. This is very useful: the component has its state which can be changed, e.g. by user interaction. The change of the state causes a “re-render” of the Virtual DOM and, as a result, some part of the user interface changes. Of course, one component may depend on another component – we can pass the state from the parent component to its children, etc. All of this is great but, as the application grows, the complexity of all these dependencies grows too. That’s why Facebook engineers invented an architecture for React applications which solves this complexity problem and they called it Flux. Today we will discuss this architecture. Moreover, I will show you what Redux is – in my opinion, the best Flux implementation!

What is Flux?

As I wrote before, Flux is just an architecture, not a library or framework. Let’s take a look at how its authors explain it:

Flux is the application architecture that Facebook uses for building client-side web applications. It complements React’s composable view components by utilizing a unidirectional data flow. It’s more of a pattern rather than a formal framework, and you can start using Flux immediately without a lot of new code.

As you can see, the only thing Flux adds to a React application is an “unidirectional data flow”. But what does that mean? I think the below image (from the official documentation) describes it best:

best flux implementation

The flow starts from the left. Firstly, the action is created by the action creator. The action is actually a plain JavaScript object which contains a type property. It can also contain other properties containing some additional data.

The action is distributed to the store by a function called dispatcher. This function actually manages the whole data flow. Every store in the application registers a callback in the dispatcher to handle incoming actions. When the action is dispatched, all these callbacks are invoked. One of them should be prepared to handle the action with the specific value of the type property.

The stores contain the whole state of the application. As I wrote before, they handle the action based on its type property in the callback function registered in the dispatcher.

The view uses the stores state in the same way as it uses the internal components state. When the state in the store changes, it re-renders the component (this is the place where React comes into play). Additionally, the view can dispatch other actions (e.g. when a user clicks a button) which changes the state and so on.

All of this is just a set of rules. How it is implemented depends on the developer. But we now have several implementations of Flux available. One of them is Redux which I will show you in the next section of this article.

The best Flux implementation? Redux!

Actually, Redux is not an exact implementation of Flux but it is strongly inspired by it. It is also inspired by the Elm architecture. Why do I think that Redux is the best Flux implementation? Well mostly because it simplifies the Flux architecture a little bit – it does not have a dispatcher concept and the store is implemented by pure reducer functions.

If you are still not convinced why Redux is the best Flux implementation, you can read a great and satisfying answer posted by its author, Dan Abramov, on stack overflow.

If you take a look at the official documentation of Redux, you can see that Redux can be described by three fundamental principles:

  • Single source of truth – the state of the whole app is stored in an object tree within a single store
  • State is read-only – the only way to change the state is to emit an action, an object which describes what is happening
  • Changes are made with pure functions – to specify how the state tree is transformed by actions, you have to write pure reducers

Ok, now that we know all the principles of Redux, we can go through the code to understand how Redux works. Luckily, we can find many good examples in the Redux source code on github. The simplest of them is counter-vanilla. It doesn’t use React so I decided to create my own example based on it and it is also available on my github.

Let’s take a look at the index.js file of the example:

import React, { PropTypes } from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';
import { connect, Provider } from 'react-redux';

const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, counter: state.counter + 1 };
    case 'DECREMENT':
      return { ...state, counter: state.counter - 1 };
    default:
      return state;
    }
};

const store = createStore(reducer, {counter: 0},window.devToolsExtension ? window.devToolsExtension() : undefined);

class Counter extends React.Component {
  static propTypes = {
    counter: PropTypes.Number,
    onIncrement: PropTypes.func,
    onDecrement: PropTypes.func
  };

  render() {
    const { counter, onDecrement, onIncrement } = this.props;

    return (
      <div>
        <div>{counter}</div>
        <button onClick={onDecrement}>-</button>
        <button onClick={onIncrement}>+</button>
      </div>
    );
  }
}

const mapStateToProps = (state) => {
  return { counter: state.counter };
};
const mapDispatchToProps = (dispatch) => {
  return {
    onIncrement: () => dispatch({ type: 'INCREMENT' }),
    onDecrement: () => dispatch({ type: 'DECREMENT' })
  }
};

Counter = connect(mapStateToProps, mapDispatchToProps)(Counter);

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

Ok, let’s talk about some parts of this code.

Reducer

The first interesting thing in the above example is the function called reducer:

const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, counter: state.counter + 1 };
    case 'DECREMENT':
      return { ...state, counter: state.counter - 1 };
    default:
      return state;
    }
};

As I wrote before, the reducer function acts as the store in Flux. It’s a state and a callback function at the same time. The function takes two parameters: state and action.

The reducer function checks the type of action and, depending on what it is, returns the new version of the state object. If the type of action has an “INCREMENT” value, it returns a new state object with the counter property incremented. If the type is “DECREMENT”, it returns a new state object decremented. In case of any other type of action, it just passes the state on.

What is important here is that the state always has to be immutable. That’s why we always return a whole new object. Please note the “spread operator” – this code:

return { ...state, counter: state.counter + 1 };

means that we return an object which has all the properties copied from the state object and, additionally, has the counter properties updated.

Creating the store

The createStore function:

const store = createStore(reducer, { counter: 0 });

is a special function provided by the Redux library which creates the Redux store. It takes the reducer as the first parameter and the initial state as the second one. If you read one of my previous posts, you should know that this is also the place where we can apply middleware.

The React component

The next thing in the code is the React component implementation:

class Counter extends React.Component {
  static propTypes = {
    counter: PropTypes.Number,
    onIncrement: PropTypes.func,
    onDecrement: PropTypes.func
  };

  render() {
    const { counter, onDecrement, onIncrement } = this.props;

    return (
      <div>
        <div>{counter}</div>
        <button onClick={onDecrement}>-</button>
        <button onClick={onIncrement}>+</button>
      </div>
    );
  }
}

If you already know React this is actually nothing special for you. The only interesting thing is that in the this.props object we have a counter property as well as onDecrement and onIncrement functions available! This is the key as to how Redux works well with React.

The counter property is the value mapped directly from the reducer’s state so every change to this value initiated by the action will be reflected in the UI. The onDecrement and onIncrement functions are called “action creators”. They actually dispatch appropriate actions.

Mapping state and dispatch to props

In the previous section we discovered that the state and action creators are available in the this.props property. Here’s how this is done – first, let’s take a look at the code which is responsible for that:

const mapStateToProps = (state) => {
  return { counter: state.counter };
};
const mapDispatchToProps = (dispatch) => {
  return {
    onIncrement: () => dispatch({ type: 'INCREMENT' }),
    onDecrement: () => dispatch({ type: 'DECREMENT' })
  }
};

Counter = connect(mapStateToProps, mapDispatchToProps)(Counter);

The mapStateToProps function gets the state and returns the new object. Actually, it could pass the state on, but if you wanted to filter some values, etc. this is the right place to do it.

mapDispatchToProps is a function which returns an object containing functions – action creators. As you can see, every action creator is a function which returns an action object. We already know that the action should contain at least the type property. If we want to pass some additional variables to these functions, this is the place where we can translate them to the action object.

The most important thing in the mapping to props task is the connect function. It takes values returned by the mapStateToProps and mapDispatchToPops functions and adds them to the this.props object of the Counter component. Please note that we re-assigned the Counter component – this is because the connect function returns the wrapped component.

Rendering

The last thing to do is to render everything on the screen. For this we use the render function of the react-dom package:

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

The important thing here is for our component to be wrapped by the Provider component (a part of the react-redux package). By passing the store into it, we make the connect function from the previous section work.

Summary

I hope you now understand what Flux architecture is and how Redux, the best Flux implementation (of course, in my opinion), works. In the React world, using Redux is very useful for managing a huge application state and minimising the amount of re-renders. But this architecture can be used not only with React. You can actually use it in every other front-end framework/technology… I wonder if you will do it?

Related Post

I recommend Nozbe

Simply Get Everything Done

Get your tasks and projects done thanks to Nozbe system and apps for the Mac, Windows, Linux, Android, iPad and iPhone.

If you want to know more about Nozbe and its capabilities, please take a look at my article about this great application.