What is React?

React is a declarative, efficient, and flexible JavaScript library for building user interfaces.

It is a UI library developed at Facebook to facilitate the creation of interactive, stateful& reusable UI components. It is used at Facebook in production, and Instagram.com is written entirely in React.

It also uses a concept called the Virtual DOM that selectively renders subtrees of nodes based upon state changes. It does the least amount of DOM manipulation possible in order to keep your components up to date.

 

To install React with npm, run:

npm install --save react react-dom

Enabling ES6 and JSX

It is recommend to use React with Babel to let you use ES6 and JSX in your JavaScript code. ES6 is a set of modern JavaScript features that make development easier, and JSX is an extension to the JavaScript language that works nicely with React.

 

The smallest React example looks like this:

importReactfrom'react';

importReactDOMfrom'react-dom';

ReactDOM.render(
       <H1>Hello World!</H1>, 
       document.getElementById('root')
);

This code renders into a DOM element with the id of root so you need

  <div id="root"> </div>

somewhere in your HTML file.JSX produces React “elements”. JSX tags may contain children:

const element=(
<div>
        <H1>Hello World!</H1>
        <H2>Good to see you here!</H2>
</div>
);

Since JSX is closer to JavaScript than HTML, React DOM uses camelCase property naming convention instead of HTML attribute names.

For example, class becomes className in JSX, and tabindex becomes tabIndex.

Babel compiles JSX down to React.createElement() calls.

React DOM compares the element and its children to the previous one, and only applies the DOM updates necessary to bring the DOM to the desired state.

This is short description of React but not enough to develop an application. For that we need Redux also, as we use library likereact-redux.

What is Redux?

As per official site of Redux,

Redux is a predictable state container for JavaScript apps.

It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.

You can use Redux together with React, or with any other view library.It is tiny (2kB, including dependencies).

Redux can be described in Three basic principles,

Single source of truth

The state of your whole application is stored in an object tree within a single store.

This makes it easy to create universal apps, as the state from your server can be serialized and hydrated into the client with no extra coding effort. A single state tree also makes it easier to debug or introspect an application; it also enables you to persist your app’s state in development, for a faster development cycle. Some functionality which has been traditionally difficult to implement – Undo/Redo, for example – can suddenly become trivial to implement, if all of your state is stored in a single tree.

console.log(store.getState()) 
/* Prints
{
    visibilityFilter: 'SHOW_ALL',
    todos: [    
           {
             text: 'Consider using Redux',
             completed: true,
           },
           {
             text: 'Keep all state in a single tree',
             completed: false
           }
   ]
}*/

State is read-only

The only way to change the state is to emit an action, an object describing what happened.

This ensures that neither the views nor the network callbacks will ever write directly to the state. Instead, they express an intent to transform the state. Because all changes are centralized and happen one by one in a strict order, there are no subtle race conditions to watch out for. As actions are just plain objects, they can be logged, serialized, stored, and later replayed for debugging or testing purposes.

store.dispatch({
   type:'COMPLETE_TODO',
   index:1
}) 

store.dispatch({
   type:'SET_VISIBILITY_FILTER',
   filter:'SHOW_COMPLETED'
})

Changes are made with pure functions

To specify how the state tree is transformed by actions, you write pure reducers.

Reducers are just pure functions that take the previous state and an action, and return the next state. Remember to return new state objects, instead of mutating the previous state. You can start with a single reducer, and as your app grows, split it off into smaller reducers that manage specific parts of the state tree. Because reducers are just functions, you can control the order in which they are called, pass additional data, or even make reusable reducers for common tasks such as pagination.

functionvisibilityFilter(state ='SHOW_ALL', action){
    switch(action.type){
    case'SET_VISIBILITY_FILTER':
    returnaction.filter
    default:
      return state
   }
} 
functiontodosList(state =[], action){
    switch(action.type){
    case'ADD_TODO':
    return[
       ...state,
    {
      text:action.text,
      completed:false
    }
    ]
    case'COMPLETE_TODO':
    returnstate.map((todo, index)=>{
      if(index ===action.index){
         returnObject.assign({},todo,{
         completed:true
      })
  }
   returntodo
  })
    default:
      return state
   }
} 
import{combineReducers,createStore}from'redux'
let reducer =combineReducers({visibilityFilter,todos})
let store =createStore(reducer)

 

Don’t worry about terms mentioned above like, Action, Reducerand State. We will elaborate them in more basic and simple way because Redux is combination of these terms together.

Actions

First, let’s define some actions.

Actions are payloads of information that send data from your application to your store. They are the only source of information for the store. You send them to the store using store.dispatch().

Here’s an example action which represents adding a new todo item:

const ADD_TODO ='ADD_TODO'
{
    type: ADD_TODO,
    text:'Build my first Redux app'
}

Actions are plain JavaScript objects. Actions must have a type property that indicates the type of action being performed. Types should typically be defined as string constants. Once your app is large enough, you may want to move them into a separate module.

import{ ADD_TODO, REMOVE_TODO }from'../actionTypes'

Action Creators

Action creators are exactly that—functions that create actions. It’s easy to conflate the terms “action” and “action creator,” so do your best to use the proper term.

In Redux action creators simply return an action:

functionaddTodo(text){
    return{
        type: ADD_TODO,
        text
    }
}

This makes them portable and easy to test.

Reducers

Actions describe the fact that something happened, but don’t specify how the application’s state changes in response. This is the job of reducers.

The reducer is a pure function that takes the previous state and an action, and returns the next state.

(previousState, action)=>newState

It’s called a reducer because it’s the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue). It’s very important that the reducer stays pure. Things you should never do inside a reducer:

  • Mutate its arguments;
  • Perform side effects like API calls and routing transitions;
  • Call non-pure functions, e.g.now() or Math.random().

It should calculate the next state and return it. No surprises. No side effects. No API calls. No mutations. Just a calculation.

The basic structure of Reducer can be given as follows,

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

When the app is larger, we can split the reducers into separate files and keep them completely independent and managing different data domains.

Finally, for combining two or more Reducers, Redux provides a utility called combineReducers().

import{combineReducers}from'redux'
 
constexApp=combineReducers({
    visibilityFilter,               // first reducer
    list                            // another reducer
})

 

exportdefaultexApp

Store

In the previous sections, we defined the actions that represent the facts about “what happened” and the reducers that update the state according to those actions.

The Store is the object that brings them together. The store has the following responsibilities:

It’s important to note that you’ll only have a single store in a Redux application. When you want to split your data handling logic, you’ll use reducer composition instead of many stores.

It’s easy to create a store if you have a reducer. We will import combined reducers usingcombineReducers(), and pass it to createStore().

 

import{createStore}from'redux'
importtodoAppfrom'./reducers'
let store =createStore(exApp)

You may optionally specify the initial state as the second argument to createStore(). This is useful for hydrating the state of the client to match the state of a Redux application running on the server.

let store =createStore(exApp,window.STATE_FROM_SERVER)

Now we need to dispatchaction using store.dispatch() method as,

store.dispatch(addAction('Learn about actions'));
store.dispatch(addAction('Learn about reducers'));
store.dispatch(addAction('Learn about store'));
store.dispatch(toggleAction(0));
store.dispatch(toggleAction(1));

Here we have completed all basic components to develop React-Redux application. Now we will see how data flows in our application execution.

Redux architecture revolves around a strict unidirectional data flow. This means that all data in an application follows the same lifecycle pattern, making the logic of your app more predictable and easier to understand. It also encourages data normalization, so that you don’t end up with multiple, independent copies of the same data that are unaware of one another.

The data lifecycle in any Redux app follows these 4 steps:

  1. You call dispatch(action).

An action is a plain object describing what happened.

  1. The Redux store calls the reducer function you gave it.

The store will pass two arguments to the reducer: the current state tree and the action.

  1. The root reducer may combine the output of multiple reducers into a single state tree.

How you structure the root reducer is completely up to you. Redux ships with a combineReducers()helper function, useful for “splitting” the root reducer into separate functions that each manage one branch of the state tree.

  1. The Redux store saves the complete state tree returned by the root reducer.

This new tree is now the next state of your app! Every listener registered with store.subscribe(listener) will now be invoked; listeners may call store.getState() to get the current state.

Now, the UI can be updated to reflect the new state. If you use bindings like React Redux, this is the point at which component.setState(newState) is called.

 

Conclusion

Redux has many elegantly designed features, and we can write a lot less repetitive code and logic.

In addition, it was a great decision to extract the portion that connects React and Redux into a library, as this way Redux won’t be directly coupled with React.

In terms of testing, any test that involves views are usually rather complex, but Redux makes it easier by making the view components “dumb”. “Dumb” components only depend on props and thus can be tested easily.

 

 

For more detailed explanation and examples you can visit React and Redux official sites, where you will find some useful Demos.