Advertisement

Redux – with React.js

Madanasekaran.P

Redux is described as a state-management tool that can be used with any client-side JavaScript library or framework , for example JQuery or Angular.js. The github page says “Redux is a predictable state container for JavaScript apps”. But it is mostly used with React.js. ((Its creator calls it a “generic” library for connecting react components to redux store “). The UI in React is composed of components .React "flows" data through these components.

More specifically, this is called "unidirectional data flow" — data flows in one direction from parent to child. In the earlier article on React.js, we saw how props and state are used to pass this data from parent to children components. The theory behind React appears to be the MVC paradigm that is good for server-side is not necessarily the best technology for the Client-side and composing the View layer from re-usable components can better serve the purpose. But the users, instead of sticking merely to React- components, preferred to use some other MVC framework like Backbone or Angular to manage data with React. In other words React was considered as a mere “V” in MVC, and for M and C other MVC frameworks were used. The two-way data-binding in these frameworks was against the grain of React. So Facebook brought out Flux paradigm within a year of the release of React.js. The opinion of senior React developers is that “Generally, React must be paired with Redux in order to make a functional single-page-app, the right way (or other similar solutions like MobX or CerebralJS)”.Redux has become the  most-used Flux implementation.

The general concept of using store(s) to coordinate application state is a pattern known as the Flux pattern. It's a design pattern that compliments unidirectional data flow architectures like React. . Flux is a pattern, not a tool; many libraries came out implementing this pattern from third parties. Redux is a tool which was inspired by the Flux pattern and Elm. Redux has gained a lot of momentum and Facebook has also employed Dan Abramov, the creator of Redux. Facebook has also released Relay, a more elaborate tool for state management with a lot of optimizations;  both Redux and Relay have their respective areas of use in a React app. For interested readers the talk, by Jared Forsyth “ Redux, Reframe, Relay, Ohm Next, oh my!” available on You Tube, which  compares the various state management tools available for React.js, is suggested.

Redux: It stores all our application state in one place, called a "store". It also provides methods to connect this redux store to React components. Components can "dispatch" actions to update the state in the store. The components that need to be aware of these state changes can "subscribe" to the store. In other words, with Redux involved, there is no direct communication between components, but rather all state changes must go through the single source of truth, the store.

The dataflow in Redux is given below.

 

  1. Store-is the central concept in this pattern .There can be only one store and it contains all Application data. The data can be updated only by passing an action to the dispatch() method in the store class. The  getState() enables a component to get the data/state from the store , and the component can use subscribe () to attach listeners for automatic updates for state changes.
  2. Actions – Action is a JavaScript object and it should have “type” attribute,  apart from any other property you want. They carry payloads of information to the store. When the store receives an action through dispatch(), the store sends the action along with the current state to the reducer passed to it, when the store was created.
  3. Reducers – they are just pure functions that take in actions and current state and return a new state. Actions describe the fact that something happened, but it is the job of a reducer to specify how the application's state changes in response to this event.  In short, reducer contains the logic to modify application data.
  4. Components subscribing to state changes are re-rendered when application state changes.

It's important to note that in a more faithful implementation of Flux you can see many stores –corresponding to different types of data we want to store in the data store.In a Redux application you'll only have a single store. When you want to split your data handling logic, you have to use many reducers and reducer composition instead of many stores.

Sample

To create our sample, first install “create-react-app” the official command line interface (CLI) for building React applications.       ` The idea is to jump into React/Redux development without a lot of the setup concerns that would be necessary to get Webpack/Babel/etc ready for development.

npm install -g create-react-app

create-react-app lrn //create app

When you get success message, you can see that you get a skeletal app “lrn”, which you can start by executing
cd lrn
 npm start.

Redux is a separate library and not a part of React.js and you have to install it explicitly by executing
  npm install –save redux.

it will take some time for npm to install redux and fetch necessary dependencies. Our first sample will not use React at all as it will not have any UI. Then, one may ask, why should you use “create-react-app CLI”. The CLI uses Web-pack server and Babel underneath. Otherwise it may require a number of steps to set up the development environment using npm and install Web-pack, Babel etc. The purpose of this sample is only testing, using JavaScript Console and see how Redux works.
 We can replace entirely the generated index.js with the following. You can see the code creates “store” and “reducer “ objects and dispatch() is invoked to update state  and subscribe() to get the updated state from the store object  :

/src/index.js

import {createStore} from "redux";

const counter = (state =0 , action) => {             //arrow function syntax used
  switch(action.type)
{
  case "INC":
   return state + 1 ;
   case "DEC":
    return state - 1;
   default:
    return state                  // default case essential to avoid undefined error
}
}
const store = createStore(counter);
store.subscribe(() => {
  console.log('store changed', store.getState())
})
store.dispatch({type: "INC" })
  store.dispatch({type: "INC"})
  store.dispatch({type: "INC"})
  store.dispatch({type: "DEC"})

You can see that there is no reference to any React API in the above code, as we have not used React. Only objects and functions from Redux module are used. The Store object in Redux holds not only the application state/data but also necessary functions to update and access the same. You can consider it as a client side data store.  

  1. createStore() from Redux module is imported and used. It returns a store taking name of a reducer
  2. You can see that the Reducer is only a call-back function that takes two arguments.1) action 2) state. It does not modify the state. It applies the action and the state and returns a new state.
 Here listener attached to subscribe() is an anonymous function that uses store.getState().
Store allows access to state via getState();
  1. Store allows state to be updated via dispatch(action);

You can execute
npm start

The Bowser will open and click F12.You can see in the console the state changes logged. The warnings and error also appear, as we have not used React.

Figure-1

Next sample:
 In this sample we will use both Redux + React. They are separate JavaScript libraries that don’t have any direct relationship. There is a library/binding react-redux to connect the two. We will see its use in the next article. Now we will bind them in our code. Redux controls an app’s state changes, while React renders the view of states.

Execute
 create-react-app Counter
and generate an application.
 cd to Counter
Install redux by executing
 npm install - -save redux

Index.js  We will replace the generated /src/index with the code given below.

/src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
//import App from './App';
import './index.css';
import { createStore } from 'redux';

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

class Counter extends React.Component {  //---------1)              
  render() {
   let {number, increase, decrease} = this.props
return <div>
     <div>{number}</div>   //---------4)
      <button onClick={increase}>+</button>  //------2)
      <button onClick={decrease}>- </button>  //-----3)
    </div>
  }
 }
const store = createStore(reducer);

const render = () => ReactDOM.render(  //-----2)
  <Counter
    number={store.getState()}  //------3)
    increase={() => store.dispatch({ type: 'INCREMENT' })}  //----4)
decrease={() => store.dispatch({ type: 'DECREMENT' })}  //--4)
  />,
document.getElementById('root')
);

render();            //-------5)
store.subscribe(render); //-------6)

  • The Counter component is just a “dumb” component that is not aware of any application logic or Redux. It has ‘number’ property and two buttons   ‘increase’ and ‘decrease’ which are just props. But these are callbacks attached to button clicks but they are not implemented here. The callbacks are passed later in the  render() method with appropriate actions . In other words, Redux states are passed as props to the React dumb components, in the render() which is redux-aware. The React dumb component is not directly related to Redux, because its behaviour is determined by its props. Whether or not the prop came from Redux does not matter to the React dumb component.

  • When you render a Component , you can pass the values its props should take.

  • The number props is given the value returned by getState() ie the current state of the store.

  • When the “+” is clicked, ‘increase’ call-back/props is passed the store.dispatch() with the action of the type: “INCREMENT”. In Redux ,the only way to mutate the internal state is to dispatch an action. When the “-” is clicked, decrease call-back/props is passed the store.dispatch()  with a different action type as argument.

  • Initial rendering of the state.

  • Because of this subscription, the render() is called, whenever there is a state change.

To use React & Redux together, in the top-level React component we set Redux’s state as the pure component’s props. When store. getState() is invoked , the  state is accessed. The state becomes “number” props of the Counter. We need to subscribe()  to the store to create a listener for changes in the store. It needs a render() method to pass state down to the dumb Component. The “index.js” holds both the render()  which is Redux-aware and Counter component which is a dumb component that only knows how to display the mark-up and the data it received in props. It has no knowledge about how the data was received or the store.

A different way of defining a Component from React 14.0 Those who are interested in defining the Counter component in a functional way, can replace the earlier Counter component class with the following:

const Counter = ({number,
increase,
decrease
}) => (
<div>
<h1>{number}</h1>
<button onClick={increase}>+</button>
<button onClick={decrease}>-</button>
</div>
);

What is the difference between Flux and Reduce?

The above question is often repeated in React circles.  Flux, as mentioned above, is an architectural guideline for building web applications. While it’s not part of React, nor was it built exclusively for React, it pairs exceptionally well with the library. The main point of Flux is to allow an uni-directional data flow in your application. It is composed of basically three pieces: actions, stores, and a dispatcher. Redux, according to the docs, is "a predictable state container for JavaScript apps." It's a very lightweight (2kB) implementation of flux. There are a number of other implementations of Flux. Redux evolves the ideas of Flux, but avoids its complexity by taking cues from Elm. The main differences between Redux and a full flux implementations are:

  • There are no discrete dispatchers in Redux; in Flux the dispatcher is an object which manages data flow between other objects; in Redux it is only  a function in store object to send an action object  to a reducer object. 
  • Redux holds your entire application's state in one place in a single store as against a typical implementation of Flux, which uses as many number of stores as the number of requests.
  • Your app's state is immutable.

Conclusion:


Composition of UI from Components, Uni-directional data-flow and virtual DOM and a “diffing” algorithm to render only the changed DOM elements -all have contributed to the success of React.js. Now other frameworks like Angular-2, Ember-2 have adopted those ideas from React.js. Facebook has also released an architectural pattern for web/React applications. This pattern scales well to large and complex apps. It also enables very powerful developer tools that make possible to trace every mutation to the action that caused it. There are a number of libraries implementing the pattern and the Redux implementation, which is influenced by Elm, seems to have gained dominance in this area. The three fundamental principles of redux are: 1)  single source of truth: The state of your whole application is stored in an object tree within a single store.2) State is read-only: The only way to change the state is to emit an action, an object describing what happened. 3) Changes are made with pure functions: To specify how the state tree is transformed by actions, you write pure reducers.

React and Redux are separate libraries and we can use them together by “manually binding them” as shown above. There is a separate biding library “ react-redux”  to bind the two. Redux can be used with any client-side JavaScript library, though it fits better with the functional composition in React.js. When you use React and Redux you can manually bind them in your code, use  a dedicated binding library like react-redux. The lessons on Redux by Dan Abramov the creator of Redux, are available on “egghead.io”. It is suggested there that “ Before you use the React Redux bindings, learn how to create a complete simple application with just React and Redux”. Readers are suggested to listen to the lessons to get a better understanding of Redux with React.  








Added on August 9, 2017 Comment

Comments

#1

Ashraf Raza commented on August 9, 2017 at 12:14 p.m.

Hi, Great article, it helped me to understand better how react handles immutable objects. Thank you.

#2

RAMESH CHAWLA commented on August 9, 2017 at 3:16 p.m.

I am not a fan of the Redux either, but it’s just the most common I see so I thought I’d go along with it.

Post a comment