AppDividend
Latest Code Tutorials

Redux Tutorial: The Complete Guide Step by Step

Redux Tutorial For Beginners

6

Redux is quite an excellent State Management Framework usually used with the React.js library. In Single Page Application, data management on the client-side is far more complicated than imagined. Now, you are familiar with that; ReactJS is relying on the State of the application. However, In React.js, state management is possible, but when the application gets bigger and bigger, unwanted errors and data changes are detected. Which module has changed which state and which view is updated? All these matters get complex, and we feel trapped in our application. Facebook gives the solutionIts developer has created one State management pattern called Flux.

What is Flux

It complements React’s composable view components by utilizing the unidirectional data flow. When the users interact with views, the views propagate actions through a central dispatcher to the various stores that hold the application data and logic, which updates all of our affected views.

Flux has so many stores, and each store uses a different small part of the state or data of our application. In other words, each different module has its store.

Redux Tutorial 2017

Flux Data Flow

  1. The user interacts with the view, and the view triggers an action.
  2. Action dispatch the corresponding function, and then that function changes the store.
  3. When the store updates its data, the subscriber views are automatically updated. Therefore, we do not need to modify the data in different modules manually.

It is a unidirectional data flow. When the application gets bigger and bigger, then multiple stores manage the data. So that scenario will look like this.

 

React Redux Tutorial 2017

When multiple stores are there, the condition of our application looks like the above figure, but the data flow is Unidirectional.

Flux has Multiple Stores.

What is Redux

Redux is the predictable state container for JavaScript applications. Redux is also following the Unidirectional flow, but it is entirely different from Flux. Flux has multiple stores.

Redux has a Single Store.

Latest Redux Tutorial Step By Step With Example From Scratch

Redux can not have multiple stores. Instead, the store is divided into various state objects. So all we need is to maintain the single store, or we can say the only source of truth.

Three Principles Of Redux

  1. Single source of truth.

  2. The state is read-only.

  3. Changes are made with pure functions.

It is the state of our whole application that is stored in an object within a single store.  The only way to change the state is to emit an action, an object describing what happened. To specify how actions transform the state, you write pure reducers.

Actions

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

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.

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

Action Creators

Action creators are exactly the functions that create actions.

function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

Reducers

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

Handling Actions

(previousState, action) => newState

This is called a reducer because it is the type of function you would pass to Array.prototype.reduce(reducer, ?initialValue). The reducer must stay pure.

Following are the things you should never do inside a reducer:

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

Store

A store is an object that brings them together. A store has the following responsibilities:

It is important to note that you will only have a single store in a Redux application. If you want to split your data handling logic, you will use reducer composition instead of many stores.
import { createStore } from 'redux'
import todoApp from './reducers'
let store = createStore(todoApp)

Redux Tutorial With Example

We are going to take an example of a simple counter application using React.js and Redux. But, first, we need to set up a react environment.

Step 1:  Configure the project.

Create one project folder and, in that, create one file called package.json. Then, copy the following code into it.

{
  "name": "reduxapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "webpack-dev-server"
  },
  "author": "KRUNAL LATHIYA",
  "license": "ISC",
  "devDependencies": {
    "babel-core": "^6.24.0",
    "babel-loader": "^6.4.1",
    "babel-preset-es2015": "^6.24.0",
    "babel-preset-react": "^6.23.0",
    "babel-preset-stage-3": "^6.22.0",
    "webpack": "^2.3.2",
    "webpack-dev-server": "^2.4.2"
  },
  "dependencies": {
    "react": "^15.4.2",
    "react-dom": "^15.4.2",
    "react-redux": "^5.0.6",
    "redux": "^3.7.2"
  }
}

Switch to a terminal and type the following command.

npm install

The next step will be to create the webpack.config.js file in the root folder.

// webpack.config.js

module.exports = {
    entry: './src/main.js',
    output: {
        filename: 'bundle.js'
    },
    module: {
        loaders: [
            {
                loader: 'babel-loader',
                test: /\.js$/,
                exclude: /node_modules/
            }
        ]
    },
    devServer: {
        port: 3000
    }
};

Also, create one file called in the root called .babelrc

{
  "presets": ["es2015", "react", "stage-3"]
}

Make one file in the root called index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Redux Tutorial 2017</title>
  </head>
  <body>
     <div id="root"></div>
  </body>
</html>

Go to a terminal and type this command.

npm start

The server will start at this URL: http://localhost:3000

Step 2: Create a main.js file inside the src folder.

// main.js

import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import App from './components/App';

render(
  <Provider>
    <App />
  </Provider>,
  document.getElementById('root')
)

I have included the react particular dependency, but also I have included react-redux. This is because it provides us a store through our entire application. So our App element is wrapped around Provider.

Step 3: Create components directory inside src.

Make one directory and inside make our most important component file called App.js.

// App.js

import React from 'react';

const App = () => {
 
 <div className="container">
   App Component
 </div>

}
export default App;

App.js is the component where our other components are included. We are creating a simple counter application. However, we need to define first how many components are required to complete the application.

There are mainly two types of components when you are dealing with React and Redux.

  1. Smart Component
  2. Dumb Component

Smart Component

The smart component is the kind of component, which directly interacts with the state of our application. It has access to the store, and it can either dispatch the actions or get the current state of our application. It is the smart component because when the store is changed, by default, it subscribes to the new state and changes the view according to it. So in our application, there are three smart components.

  1. Counter.js
  2. AddCounter.js
  3. RemoveCounter.js

These smart components are put in the containers folder, which I will create later in this article.
Container components only contain those components that are smart.

Dumb Component

App.js is the Dumb component; it includes the child component but, it does not interact with the store. So we put that component inside the components folder.

Step 4: Create container dir inside the src folder.

We need to create three container components inside this directory, as I have mentioned before.

  1. We are creating the AddCounter.js component.
// AddComponent.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addCounter } from '../actions';
import { bindActionCreators } from 'redux';

class AddCounter extends Component {
  constructor(props) {
        super(props);
   }
   render() {
     return (
           <div className="container">
            <form>
              <div className="field is-grouped">
                <div className="control">
                  <button className="button is-primary" 
                    onClick={(e) => {e.preventDefault();this.props.dispatch(addCounter())}}>
                      Add
                  </button>
                </div>
              </div>
            </form>
            </div>
     )
   }
}
function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(addCounter, dispatch) }
}
export default connect(mapDispatchToProps)(AddCounter);

Here, I need to explain lots of things, so let us get started.

If the AddCounter component is a container component, then it connects to the store. Remember, that is why it is a smart component.

So the last line of the code is that we are connecting our component to the Redux store.

When the user clicks the button according to the Redux principle, it dispatches an action, so we need to pass the dispatch function as a property to this component.

Now, it dispatches the action, and in our scenario, it is named addCounter(). So addCounter return an action.

Create an Action

Make one folder inside src called actions and in that create one file called index.js.

// index.js

import * as actionType from './ActionType';

export const addCounter = () => ({
  type: actionType.ADD_COUNTER,
  payload: 1
});

So as I mentioned, It returns an object that describes our actions.

Here, I have also included one more file called ActionType.js

This file is needed because all the action names are constant, and if we create one file, which only exports the naming constant, then it is easy for us to define any action without any typos because actions names are on the strings.

Make ActionType.js

This file is inside the actions directory.

// ActionType.js

export const ADD_COUNTER = 'ADD_COUNTER';
export const REMOVE_COUNTER = 'REMOVE_COUNTER';

Now, coming to the point, we are at the AddCounter.js file.

// AddCounter.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { addCounter } from '../actions';
import { bindActionCreators } from 'redux';

class AddCounter extends Component {
  constructor(props) {
        super(props);
      }
   render() {
     return (
           <div className="container">
            <form>
              <div className="field is-grouped">
                <div className="control">
                  <button className="button is-primary" 
                    onClick={(e) => {e.preventDefault();this.props.dispatch(addCounter())}}>
                      Add
                   </button>
                </div>
              </div>
            </form>
            </div>
     )
   }
}
function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(addCounter, dispatch) }
}
export default connect(mapDispatchToProps)(AddCounter);

Function mapDispatchToProps is needed because we need to pass dispatch as a property to our component, and also, we need to bind the actions with this component.

Step 5: Create reducer directory inside src and make one file

Make one file called counterReducer.js inside the reducer directory.

// counterReducer.js

import * as actionType from '../actions/ActionType';

const counterReducer = (state = 0, action) => {
  let newState;
  switch (action.type) {
    case actionType.ADD_COUNTER:
      return newState = state + action.payload;
    case actionType.REMOVE_COUNTER:
      return newState = state - action.payload;
    default:
      return state
  }
}

export default counterReducer;

Please note that I have described both cases here

  1. Increment (for add +1 in counter state)
  2. Decrement (decrease one from the counter state)
If you carefully see the above cases then, I have not modified the state directly. See, I have defined a new variable and then assign a new state in that variable and return that variable.
So, it is a pure function, which is not mutating any store state, take the old state value and add that old value plus the new value and assign it to the variable and return the new state of our application. This is the central principle of Redux, after all.

Make one file inside the reducer directory called index.js

// index.js

import { combineReducers } from 'redux';
import counterReducer from './counterReducer';

const counterApp = combineReducers({
  counterReducer
})

export default counterApp

Now, this is our single and final store. This is the store we include in our main.js file.

combineReducer function, as the name suggests, to combine all reducers in one store and return as a global application state object.
Now, our main.js file will look like this. I have passed the store to our entire application. Also Included are the reducers.
// main.js

import React from 'react';
import { render } from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from './components/App';
import reducer from './reducers';

const store = createStore(reducer);

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

Step 6: Create the same smart component for RemoveCounter.js

Make RemoveCounter.js inside the container directory.

// RemoveCounter.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { removeCounter } from '../actions';
import { bindActionCreators } from 'redux';

class RemoveCounter extends Component {
  constructor(props) {
    super(props);
  }
   render() {
     return (
           <div className="container">
            <form>
              <div className="field is-grouped">
                <div className="control">
                  <button className="button is-primary" 
                      onClick={(e) => {e.preventDefault();this.props.dispatch(removeCounter())}}>
                      Remove
                  </button>
                </div>
              </div>
            </form>
            </div>
     )
   }
}
function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(removeCounter, dispatch) }
}

export default connect(mapDispatchToProps)(RemoveCounter);

Now, switch to src  >>  actions  >>  index.js and add new action for removeCounter. So our final file looks like this.

// index.js

import * as actionType from './ActionType';

export const addCounter = () => ({
  type: actionType.ADD_COUNTER,
  payload: 1
});

export const removeCounter = () => ({
  type: actionType.REMOVE_COUNTER,
  payload: 1
});

We have already defined the decrement reducer.

// counterReducer.js

import * as actionType from '../actions/ActionType';

const counterReducer = (state = 0, action) => {
  let newState;
  switch (action.type) {
    case actionType.ADD_COUNTER:
      return newState = state + action.payload;
    case actionType.REMOVE_COUNTER:
      return newState = state - action.payload;
    default:
      return state
  }
}

export default counterReducer;

Step 7: Now final smart component remains is Counter.js

// Counter.js

import React, { Component } from 'react';
import { connect } from 'react-redux';

class Counter extends Component {
  constructor(props){
    super(props);
  }
  render(){
    return (
      <div className="cotainer">
        <div className="notification">
          <h1>
          {this.props.count}
          </h1>
        </div>
    </div>
    )
  }
}
function mapStateToProps(state){
  return {
    count: state.counterReducer,
  };
}
export default connect(mapStateToProps)(Counter);

This is the smart component, so we need to connect it with the Redux store. So we have connected it with the store and fetched the latest state from the store, and display it.

mapStateToProps maps the state to the props of the current component and shows the data as a property of the component.

Step 8: Include all the components into the App.js file.

// App.js

import React from 'react';
import Counter from '../containers/Counter';
import AddCounter from '../containers/AddCounter';
import RemoveCounter from '../containers/RemoveCounter';

const App = () => {
  return (
    <div className="container">
      <Counter></Counter><br />
      <div className="columns">
        <div className="column is-11">
          <AddCounter></AddCounter>
        </div>
        <div className="column auto">
          <RemoveCounter></RemoveCounter>
        </div>
      </div>
      </div>
  )
}
export default App;

Finally, all the code is over, and if you have not started the development server, please start via the following command.

npm start

If you switch to this URL: http://localhost:3000.

 

react-redux tutorial 2017

Finally, our Redux Tutorial For Beginners With Example From Scratch is over. I have put this code on Github.

Fork Me On Github

Steps to use Github

  1. Clone the repository.
  2. Go to the project folder and type this command: npm install
  3. Start the development server by this command: npm start
  4. Switch to this URL: http://localhost:3000
6 Comments
  1. Tanu says

    suppose a component is there which has 3 input fields and i render that component inside parent component . how can the object of the 3 input fields be created and sent to the parent ???

  2. Max Bisurgi says

    Hey Krunal! Nice tutorial from Redux, if it does not mind, I put a link to this post on a post I am writing about HOC. Hope you could also check it out!
    Bye!

  3. Kanwaljeet Singh Kalra says

    Hi Krunal, I think the main redux flow can be further simplified, by connecting only the app container to the store. That way, all the three components Counter, AddCounter and RemoveCounter won’t have to have the knowledge of redux dispatch. they all can just use the prop chain. To depict this, I have forked your repos and added a commit https://github.com/KKS1/ReactReduxStore/commit/070e28772446d8c93793c371cacedd69d9f8fee5
    Hope it helps !

    Best,
    Kanwaljeet

  4. Dhinesh says

    Hi bro, this is one of the greatest source to learn redux. This aritcle makes redux simple. Great work!!!! Thanks a lot!!!

  5. Drake says

    Can we only pass `mapDispatchToProps` to `connect` function? I thought the first argument is `mapStateToProps`

  6. Premal Katigar says

    Hello. Your code is good. There is one change. You need to pass store in provider otherwise it occurs error.

Leave A Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.