Introduction to Redux Actions and Reducers
Tags: react, redux, webdev, javascript
Published: 2021-01-25 01:47:47

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


With Redux, we can use it to store data in a central location in our JavaScript app. It can work alone and it’s also a popular state management solution for React apps when combined with React-Redux.

In this article, we’ll look at how to create actions that we can dispatch to our store with Redux.

### Create a Store with a Single Reducer

We can create a store with a single reducer by creating a reducer function. Then we can use Redux’s `createStore` function to create the store from the reducer.

With the store, we get to subscribe to it to get the latest values, and also dispatch actions with it to update the state in the store by passing it to the reducer.

For example, we can write the following code to create the store and run some actions:

```
import { createStore } from "redux";

function todosReducer(state = [], action) {
  switch (action.type) {
    case "ADD_TODO":
      return [...state, action.todo];
    case "REMOVE_TODO":
      return state.filter(todo => todo !== action.todo);
    default:
      return state;
  }
}

let store = createStore(todosReducer);

store.subscribe(() => console.log(store.getState()));

store.dispatch({ type: "ADD_TODO", todo: "eat" });
store.dispatch({ type: "ADD_TODO", todo: "drink" });
store.dispatch({ type: "REMOVE_TODO", todo: "eat" });
```

In the code above, we created the `todosReducer` to receive the dispatched actions and then manipulate the state as we wish to do.

We have the `switch` statement to check the action’s `type` and then act accordingly.

The action `type` is indicated in the object that we passed into the `dispatch` method.

If the action type is `“ADD_TODO”` , then we insert the `todo` item in object we have in `dispatch` ‘s argument to the end of the array, and we spread all the old values before it.

If the action type is `“REMOVE_TODO”` , then we return a new array that excludes the todo item with the given `todo` text.

Otherwise, we return what we already have.

Then we use the `createStore` method to create the store so we can call `dispatch` to pass in plain objects to manipulate the data in the store.

We can also `subscribe` to it and then call `getState()` to get the latest values.

Note that we always make a copy of `state` and then return something new with it. This prevents accidental changes from mutating objects unintentionally.

### Create a Store with a Multiple Reducers

In most apps, we want to store more than one kind of data in our store. We can do that by creating multiple reducers and then use the `combineReducer` function from Redux to combine them into one store.

To do this we can write something like the following code:

```
import { createStore, combineReducers } from "redux";

function todosReducer(state = [], action) {
  switch (action.type) {
    case "ADD_TODO":
      return [...state, action.todo];
    case "REMOVE_TODO":
      return state.filter(todo => todo !== action.todo);
    default:
      return state;
  }
}

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

let reducers = combineReducers({
  todos: todosReducer,
  count: countReducer
});
let store = createStore(reducers);

store.subscribe(() => console.log("todos", store.getState().todos));
store.subscribe(() => console.log("count", store.getState().count));

store.dispatch({ type: "ADD_TODO", todo: "eat" });
store.dispatch({ type: "ADD_TODO", todo: "drink" });
store.dispatch({ type: "REMOVE_TODO", todo: "eat" });

store.dispatch({ type: "INCREMENT" });
store.dispatch({ type: "DECREMENT" });
```

In the code above, we have 2 reducers — `todoReducer` and `countReducer` .

We combined them into one by calling Redux’s `combineReducers` function with the name of the state as the property name and the reducer function as the value.

`combineReducers` combines all the reducers into one reducer, so we can pass it into `createStore` . We can choose any state name we want.

The store is created by passing the big reducer returned from `combineReducers` .

Then in the `subscribe` callbacks, we can use `store.getState()` to get all the states. Then we can get the todos with the `todos` property and the `count` state with the `count` property.

In the `console.log` s, we should get something like:

```
todos ["eat"]
count 0
todos ["eat", "drink"]
count 0
todos ["drink"]
count 0
todos ["drink"]
count 1
todos ["drink"]
count 0
```

This is because we subscribed to the store and then get the state from each reducer individually.

The `dispatch` method is called as we did with the single reducer example.

We still pass in the action type and payload if there is one.

Since `dispatch` works the same as no matter how many reducers we have in the store, we should make sure that no 2 actions have the same name.

![](https://cdn-images-1.medium.com/max/800/0*XBY06lYZ_KgkjeBn)Photo by [Roberto Nickson](https://unsplash.com/@rpnickson?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

### Notes

`combineReducers` will throw errors in some cases to reduce the chance of committing bugs.

It’ll throw an error if a reducer function doesn’t return the `state` given to it as the first argument if the action isn’t recognized.

Also, it must never return `undefined` . It’s too easy to do this via an early `return` statement. Therefore, `combineReducers` will throw an error if we do that instead of letting the error manifest somewhere else.

If the `state` given to it is `undefined` , it must return the initial state for the specific reducer. This means that the initial state can’t be `undefined` .

We can specify the initial state as the default argument for the `state` parameter.

Redux will check for these rules when we’re writing our code.

### Conclusion

We can create a store from one more reducer function. The only difference is that we have to use `combineReducers` to combine multiple reducers into one big reducer in order to pass it into `createStore` . We can pass in a single reducer straight into `createStore` .

Then we can use `getState` to get the latest returned state of all reducers. The states are available from `getState()` and we can get the properties from the returned object of `getState` to get those states.

Dispatching actions is the same regardless of how many reducers we have in our store.