Table of Content



This time I going to take the time to research and write about Redux in combination with React, one of the hottest libraries for front-end web development. It was created in 2015, influenced by Flux architecture and became popular very quickly because of it's simplicity, excellent documentation and size (2 KB). Also is very easy to use redux with react. Let’s start with the basics:

What is Redux?

According to the official site Redux is defined as a predictable state container for JavaScript apps. Basically Redux maintains the state of an entire application in a single immutable state tree (object). This object can’t be changed directly. When something changes, a new object is created (using actions and reducers). The main goal of Redux is to facilitate the task of connect sources of different environments like for example APIs and sockets.

Redux with React.

Redux is kind of 'created' to work with React.js but also can be used with Angular.js, Backbone.js or just vanilla JS.

How to install it?

To install the stable release (through npm as package manager with a module builder like Webpack or Browserify to use modules of CommonJS):

npm i -S redux

Also you may want to install the connection to React and the developer tools.

npm i -S react-redux

npm i -D redux-devtools

Core concepts of Redux

1 – Actions.

The actions, summarized actions are events. The action task is to send data from the application (user interactions, internal events such as API calls, and form submissions) to the store. The only way to pass information to the store is through actions. The actions are POJO (Plain Old JavaScript Objects) with at least one property that indicates the action type and, if necessary, others properties indicating any other necessary data to do the action. Normally they use the format defined in FSA.

An action example:

{ type: 'TODO_APP', payload: { text: 'How to learn Redux, }, }

Actions are created with action creators. They are just functions that return actions.

function myAction(someText) { return { type: TODO_APP, payload: someText } }

To call an action anywhere in our app must be through dispatch method, like this:

// to send an action to the Store (The concept of Store will be seen ahead). Store.dispatch (myAction(someText));

2 – Reducers.

While the actions describe that ‘something’ happen they don’t specify how our app reacts to that ‘something’. In Redux, reducers are functions (pure, I will explain what a pure function is later) that take the current state of the application and an action and then return a new state.

(prevState, action) => nextState

Here is a very simple reducer that takes the current state and an action as arguments and then returns the next state:

function handleAuth(state, action) { return _.assign({}, state, { auth: action.payload }); }

Some things you should never do in a reducer:

Modify the arguments directly (the right way is to create a copy first.)

Do actions with secondary effects like API calls or change a route.

The name we put to the reducer is used as property of ‘store’ we created and is where will be saved the state returned from the reducer.

3 – Store

Store is the object that holds the application state and provides a few helper methods to access the state, dispatch actions and register listeners. The entire state is represented by a single store. Any action returns a new state via reducers.

The store has four main responsibilities:

Store the global state of the app.

Give access to the state through store.getState()

Allow the update of the state through store.dispatch()

Register listeners through store.subscribe(listener)

Take this as example:

import { createStore } from 'redux'; let store = createStore(rootReducer); let authInfo = {username: 'alex', password: '123456'}; store.dispatch(authUser(authInfo));

This image illustrates the work flow of Redux.



Redux data flow (Image: Tanya Bachuk)

The three principles of Redux.

- Single data source: The app state stores in one objet tree inside a unique STORE.

- The state is read only: The only way of change the state is through ACTIONS.

- Changes are made with pure functions: To specify how the state tree is transformed by actions, you write pure reducers.

Where can Redux be used?

Contrary of what you may be thinking, the only use of Redux isn't with React. It can be integrated with any other library/framework like for example Vue.js, Polymer, Ember, Backbone.js or Meteor, but Redux plus React, though, is still the most common combination.

Integrating Redux with React: Installing react-redux

The connection of Redux with React isn´t included directly inside Redux, in order to achieve this, we need to download react-redux:

npm i -S react react-dom react-redux redux

Encapsulating the app.

First we need to encapsulate our app with the component Provider that comes with react-redux. This component receives a unique parameter called store which one is the instance of the STORE we are using. See the follow example.

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

This component Provider defines in the global context of React our instance of store.

Accessing the store.

Now is time to define what components are going to Access our Store, because not all of them will need to. In order to do that we need to connect our Redux components to Redux, this can be achieved with a decorator that came with react-redux called connect.

// Importing the decorator @connect of react-redux import { connect } from 'react-redux'; import React from 'react'; import UserItem from './UserItem'; // Aplying the decorator @connect to our component. @connect() class UserList extends React.Component { render() { // Rendering the user list we receive from Store . return ( <section> { this.props.users .map(user => <UserItem {...user} key={user.id} />) } </section> ); } } export default UserList;

This way our component UserList will have inside it props all the data of the Store. With this we can render our app using the data stored in the Redux Store.

Pure functions vs Impure functions:

Pure Functions

A function is considered pure if:

a) It always returns the same value when given the same arguments.

b) It does not modify anything (arguments, state, database, I/O, ..).

Examples of Pure Functions (in JavaScript):

function add(x, y) { return x+y; }

function getLength(array) { return array.length; }

Impure Functions

A function is considered impure if it is not pure, typically because:

a) it makes use of an external or random value. (It stops being entirely contained and predictable.)

b) It performs an external operation, in other words it causes side effects.

var x = 5; function addToX(a) { return a+x; / Use of an external variable }

Example: A complete reducer with tests (can use a library for this like Expect.js).

You might be interested in:

const counter = (state = 0, action) => { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } } expect( counter(0, {type: 'INCREMENT'}) ).toEqual(1); expect( counter(1, {type: 'INCREMENT'}) ).toEqual(2); expect( counter(2, {type: 'DECREMENT'}) ).toEqual(1); expect( counter(1, {type: 'DECREMENT'}) ).toEqual(0); expect( counter(1, {type: 'DECREMENT Else'}) ).toEqual(1); expect( counter(undefined, {}) ).toEqual(0); console.log('Tests passed!');

Why would I need to use Redux? (extracted from this article)

Predictability of outcome:

There is always one source of truth, the store, with no confusion about how to sync the current state with actions and other parts of the application.

Maintainability:

Having a predictable outcome and strict structure makes the code easier to maintain.

Organization:

Redux is stricter about how code should be organized, which makes code more consistent and easier for a team to work with.

Server rendering:

This is very useful, especially for the initial render, making for a better user experience or search engine optimization. Just pass the store created on the server to the client side.

Developer tools:

Developers can track everything going on in the app in real time, from actions to state changes.

Community and ecosystem:

This is a huge plus whenever you’re learning or using any library or framework. Having a community behind Redux makes it even more appealing to use.

Ease of testing:

The first rule of writing testable code is to write small functions that do only one thing and that are independent. Redux’s code is mostly functions that are just that: small, pure and isolated.

Pure functions:

return a new value based on arguments passed to them. They don’t modify existing objects; instead, they return a new one. These functions don’t rely on the state they’re called from, and they return only one and the same result for any provided argument. For this reason, they are very predictable.

Because pure functions don’t modify any values, they don’t have any impact on the scope or any observable side effects, and that means a developer can focus only on the values that the pure function returns.

CONCLUSION

Redux has a growing popularity and is even bigger every day. Companies like Uber and Twitter and projects like WordPress are using it successfully in production. Redux isn’t a perfect fit for everything but we recommend to check it out. If you are up to it you can deep your knowledge over here, a tutorial from the Redux creator and see this example contains source code of Todo List app using Redux with React.