Redux for Beginners – Learn Redux with Code Examples

Redux for Beginners – Learn Redux with Code Examples

Redux can be confusing for beginner React developers to understand. There are a lot of concepts you need to know to use it properly, like reducers, actions, store, pure functions, immutability, and much more.

But every React developer should know the basics of how to work with Redux since industry projects often use Redux to manage larger projects.

So in this article, we'll explore the basics of Redux and how to use it.

Here's a preview of the app which we'll be building in the Mastering Redux course. It's a great project you can add to your portfolio and resume.

Note that, in this app, I have used INR as the currency for displaying the prices but you can easily change it to USD or AUD or any other currency with a single configuration change in the app.

What Is Redux?

Redux is a state management library that helps to better manage state in the application.

Redux library is not specific to React. It's a library that you can use in any other library or framework like Angular, Vue and even vanilla JavaScript.

But Redux is mostly used when working with React.

Redux provides a single store that we can use to manage a large amount of data.

How to Get Started with Redux

Let's create a new React project to learn Redux basics.

Execute the following command in the terminal/command prompt to create a new React project using create-react-app:

npx create-react-app redux-demo

npx in this case allows us to use the create-react-app npm package to create a new React project without installing it on our local machine.

Once the project is created delete all the files from the src folder and create a new file index.js inside the src folder.

Now open the terminal again and execute the following command from the redux-demo folder:

npm install redux@4.1.0

The above command will install the redux library with version 4.1.0 to use in our project which is the latest version at the time of writing this article.

How to Create the Redux Store

In Redux, the store is used to manage and track the changing data in the application.

To create a store we need to import the createStore function like this:

import { createStore } from 'redux';

The createStore function accepts three arguments:

  • the first argument is a function that is normally known as a reducer (required)
  • the second argument is the initial value of the state (optional)
  • the third argument is an enhancer where we can pass middleware If any (optional)

You will see how to create your own middleware as well as use the already available middleware libraries in the course.

Take a look at the below code:

import { createStore } from 'redux';

const reducer = (state, action) => {
  console.log('reducer called');
  return state;
};

const store = createStore(reducer, 0);

Here, we've first defined a reducer function using ES6 arrow function syntax. You can use the normal function instead of the arrow function If you want.

Inside the reducer function, we're logging some text to the console and then returning the value of the state from the function.

Then we pass that reducer function to the createStore function as the first argument and 0 as the initial value of the state as the second argument.

The createStore function returns a store that we can use to manage the application data.

The reducer function receives state and action as the parameters.

The initial value of the state which we passed as 0 for the createStore function is automatically passed as the value of the state parameter.

But it's a much more common practice to initialize the state inside the reducer itself rather than passing it as a second argument to the createStore function like this:

import { createStore } from 'redux';

const reducer = (state = 0, action) => {
  console.log('reducer called');
  return state;
};

const store = createStore(reducer);

Here, we're using ES6 default parameter syntax for initializing the state parameter to value 0.

Once the store is created, we can use the subscribe method provided by the store to subscribe to the changes in the store as shown below:

store.subscribe(() => {
  console.log('current state', store.getState());
});

Here, using the subscribe function, we're registering a callback function that will be called once the store is changed.

And inside the callback function, we're calling the store.getState method to get the current value of the state.

Now, open the src/index.js file and add the following contents inside it:

import { createStore } from 'redux';

const reducer = (state = 0, action) => {
  console.log('reducer called');
  return state;
};

const store = createStore(reducer);

store.subscribe(() => {
  console.log('current state', store.getState());
});

Now, If you run the application by executing the npm start command from the terminal and access http://localhost:3000/, you will see the reducer called message printed in the console.

reducer_log.png

This is because the reducer gets called immediately once we pass it to the createStore function.

How to Change the Store

Now, we're done with creating the store. But the store is not much of use right now. Because the store is connected using the reducer function but we have not added any code inside the reducer to manage the store. So let's do that.

The only way to change the store is by dispatching actions.

An action is an object sent to the store like this:

store.dispatch({
  type: 'INCREMENT'
})

Here, we're calling the dispatch function available on the store to send an action with the type INCREMENT to the store.

The dispatch function takes an object as a parameter which is known as action.

The action must have a type property as shown above. If you don't pass the type property then you will get an error.

It's a common practice and recommended to specify the type value in uppercase.

The type can be any operation you want to perform like ADD_USER, DELETE_RECORD, GET_USERS and so on.

If you've multiple words you can separate them with underscores like this { type: 'INCREMENT_NUMBER' }.

Now, open the index.js file and replace its contents with the following code:

import { createStore } from 'redux';

const reducer = (state = 0, action) => {
  if (action.type === 'INCREMENT') {
    return state + 1;
  } else if (action.type === 'DECREMENT') {
    return state - 1;
  }

  return state;
};

const store = createStore(reducer);

store.subscribe(() => {
  console.log('current state', store.getState());
});

store.dispatch({
  type: 'INCREMENT'
});

store.dispatch({
  type: 'INCREMENT'
});

store.dispatch({
  type: 'DECREMENT'
});

Now, If you run the application by executing the npm start command from the terminal, you will see the following logs printed in the console.

changing_store.png

As you can see for every action dispatched to the store, the store gets changed and so we're able to see the different values of the state in the console.

In the above code, our reducer function looks like this:

const reducer = (state = 0, action) => {
  if (action.type === 'INCREMENT') {
    return state + 1;
  } else if (action.type === 'DECREMENT') {
    return state - 1;
  }

  return state;
};

Whenever we call the store.dispatch function, the reducer function will be called and whatever returned from the reducer will become the new value of the store.

So when the first time we dispatch an action to the store like this:

store.dispatch({
  type: 'INCREMENT'
});

the first If condition inside the reducer function will be executed that will increment the state value to 1 which was initially initialized to 0 using ES6 default parameter syntax and it will be returned from the reducer function.

Note that we're using the value of the state to calculate the new value and we're not modifying the original state value like this:

if (action.type === 'INCREMENT') {
   state = state + 1;
   return state;
}

So the above code is wrong because in reducer we should not modify the original state. Doing so will create issues in your application and is not recommended.

You will learn why we don't directly change the state and various ways of creating copies of array and object in detail in the course.

And because we've added store.subscribe function in the index.js file, we're getting notified about the changing store as we can see the logs in the console.

So when we again call the dispatch with type INCREMENT, the first If condition will be executed again so 1 will be added to the previous state value which was 1 and the final state value will become 2.

Then we're dispatching the DECREMENT action to the store like this:

store.dispatch({
  type: 'DECREMENT'
});

which will execute the else condition inside the reducer and it will decrement the state value by 1 so 2 - 1 will become 1.

Note that, inside the reducer, we're also returning state at the end so If none of the condition matches, the default previous state will be returned from the function.

It's a common practice to use a switch statement inside the reducer instead of the if-else condition like this:

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

In addition to the type, we can also pass extra information as a part of the action.

Replace the contents of the index.js file with the following code:

import { createStore } from 'redux';

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

const store = createStore(reducer);

store.subscribe(() => {
  console.log('current state', store.getState());
});

store.dispatch({
  type: 'INCREMENT',
  payload: 1
});

store.dispatch({
  type: 'INCREMENT',
  payload: 5
});

store.dispatch({
  type: 'DECREMENT',
  payload: 2
});

Now, If you run the application by executing the npm start command from the terminal, you will see the following logs printed in the console.

with_payload.png

Here, while dispatching an action to the store, we're passing a payload with some value which we're using inside the reducer to increment or decrement the store value.

Here, we've used payload as a property name but you can name it whatever you want.

Our reducer function looks like this now:

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

So when we dispatch actions with type INCREMENT like this:

store.dispatch({
  type: 'INCREMENT',
  payload: 1
});

store.dispatch({
  type: 'INCREMENT',
  payload: 5
});

the following code from the reducer will be executed

return state + action.payload;

which will first add 1 and then 5 to the previous value of the state so we go from 1 to 6 and because of the DECREMENT action type

store.dispatch({
  type: 'DECREMENT',
  payload: 2
});

we go from 6 to 4 so the final value of the store will become 4.

Here's a Code Sandbox Demo.

Thanks for reading!

This was a quick introduction to Redux from my Mastering Redux course.

In the Mastering Redux course, you will learn:

  • Basic and advanced Redux
  • How to manage the complex state of array and objects
  • How to use multiple reducers to manage complex redux state
  • How to debug Redux application
  • How to use Redux in React using react-redux library to make your app reactive.
  • How to use redux-thunk library to handle async API calls and much more

and then finally we'll build a complete food ordering app from scratch with stripe integration for accepting payments and deploy it to the production.

Today is the last day to get the Mastering Redux course at a discounted price.

So click the below image to get the course at just $12 instead of the original price of $19.

You will also get a free copy of my popular Mastering Modern JavaScript book If you purchase the course till 19th May 2021.

Want to stay up to date with regular content regarding JavaScript, React, Node.js? Follow me on LinkedIn.

Did you find this article valuable?

Support Yogesh Chavan by becoming a sponsor. Any amount is appreciated!