React useReducer. Easier than we think.
Tags: react, javascript, frontend, reactnative
Published: 2023-07-18 10:02:30

## useReducer:
_**useReducer**_ is one of the most popular react hooks. _useReducer_ hook returns the current stage and a dispatch method. It is similar to the useState hook. If we want to make _complex logic_ then useReducer may be very useful.

If you want to download the full demo project then click here [Demo git](https://github.com/abdullahmubin/useReducer).

## Syntax:

`useReducer(<reducer>, <initialState>)`
`useReducer(<reducer>, <initialState>, <init>)`

Here, **reducer** function contains custom state _logic_ and the **initialState** can be a sample default state value. 

_init_ is a function and it is used whenever we want to create the initial state lazily.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/osl4a8tixgq5xmsionpt.png)



## reducer:
A **reducer** is a function that is able to process user _instruction/action_. A reducer processes the _existing state_ with user action and returns the _new state_. 

below we will try to make a simple application for better understanding. 


## Todo Application:

The below image shows the UI of our application.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgijk66fw6o7yk4ap6gi.png)


We can see that it contains a submit button, if we save it then it will show on the list, we can complete and remove that todo item.


> **We will make our code as simple as we can.**



let try to make _action type_

Here, we will make 3 types of action,

- Add Todo
- Remove Todo
- Complete Todo

I have created a new folder inside the **src** directory and the folder name is **action**. inside that folder, I have created an **index.js** file and put the below code.

```
// src/action/index.js

export const ADD_TODO = "ADD_TODO";
export const REMOVE_TODO = "REMOVE_TODO";
export const COMPLETE_TODO = "COMPLETE_TODO";

```
We have created three constants for user _action types_.

let try to make **reducer**

We already know that a **reducer** basically is a function that contain complex logic. We need to pass value and instruction/action then it will change previous state to new state. Just like **Redux** but we don't need to initialize our reducer here.

I have created a new folder and named it reducer, inside that folder I have created an index.js file and put the below code,


```
import { ADD_TODO, REMOVE_TODO, COMPLETE_TODO } from './../action'

const reducer = (state, action) => {
    switch (action.type) {
        case ADD_TODO:
            const newTodo = {
                id: action.id,
                text: action.text,
                completed: false
            };
            return [...state, newTodo];
        case REMOVE_TODO:
            return state.filter((todo) => todo.id !== action.id);
        case COMPLETE_TODO:
            const completeTodo = state.map((todo) => {
                if (todo.id === action.id) {
                    return {
                        ...todo,
                        completed: !todo.completed
                    };
                } else {
                    return todo;
                }
            });
            return completeTodo;
        default:
            return state;
    }
};
export default reducer;

```

Inside the **reducer** function, we used a _switch_ statement to check user action. If the user want to add _new todo_, then the action type will be _ADD_TODO_ and based on switch statement, it will perform _ADD_TODO_ **logic** in that block. Finally it will return _new state_.

`case ADD_TODO:
            const newTodo = {
                id: action.id,
                text: action.text,
                completed: false
            };
return [...state, newTodo];`

To **Remove** a todo task, the action type will be _REMOVE_TODO_, and based on the _switch _ statement, it will perform _REMOVE_TODO_ logic in that block. Finally, it will _return_ to the _new state_.

`case REMOVE_TODO:
            return state.filter((todo) => todo.id !== action.id);`

To **complete** a _todo_, the action will be _COMPLETE_TODO_ and it will perform his logic and return new state.

`case COMPLETE_TODO:
            const completeTodo = state.map((todo) => {
                if (todo.id === action.id) {
                    return {
                        ...todo,
                        completed: !todo.completed
                    };
                } else {
                    return todo;
                }
            });
 return completeTodo;`

it's a **simple example** so I haven't divided _UI_ into separate containers. I put everything inside _app.js_ file.

let **put useReducer** in app.js

```
import { useReducer, useState } from "react";
import "./index.css";
import reducer from "./reducer";
import { ADD_TODO, REMOVE_TODO, COMPLETE_TODO } from './action'
export default function App() {
  const [id, setId] = useState(0);
  const [text, setText] = useState("");
  const initialState = [
    {
      id: id,
      text: "First todo Item",
      completed: false
    }
  ];

  //We could also pass an empty array as the initial state
  //const initialState = []

  const [state, dispatch] = useReducer(reducer, initialState);
  const addTodoItem = (e) => {
    e.preventDefault();
    const newId = id + 1;
    setId(newId);
    dispatch({
      type: ADD_TODO,
      id: newId,
      text: text
    });
    setText("");
  };
  const removeTodo = (id) => {
    dispatch({ type: REMOVE_TODO, id });
  };
  const completeTodo = (id) => {
    dispatch({ type: COMPLETE_TODO, id });
  };
  return (
    <div className="App">
      <h2>Todo Example</h2>
      <form className="input" onSubmit={addTodoItem}>
        <input value={text} onChange={(e) => setText(e.target.value)} />
        <button disabled={text.length === 0} type="submit">+</button>
      </form>
      <div className="todos">
        {state.map((todo) => (
          <div key={todo.id} className="todoItem">
            <p className="">{todo.completed ? <del>{todo.text}</del> : todo.text}</p>
            <div className="actionType">
              <span onClick={() => removeTodo(todo.id)}>✕</span>
              <span onClick={() => completeTodo(todo.id)}>✓</span>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

```

In the above code, we can see that **useReducer** takes the _reducer function_ and _initialState_ as a _parameter_ then it returns _state_ and _dispatch_.


When someone types some _text_ and clicks on **+ sign**, then inside the _addTodoItem_ function _dispatch function_ will be called and it contains _3 parameters_ those are _type (ADD_TODO)_, _id_ and _text_. dispatch will trigger _reducer function_ and based on _type_ reducer function will add a new todo item and _return new state_.

`dispatch({
      type: ADD_TODO,
      id: newId,
      text: text
    });`


When someone _clicks_ on **✕ the sign**, then another _dispatch function_ will be called, this time type will be _REMOVE_TODO_, and based on _type_ and _id_, the _reducer function_ _removes_ the specific item and will return _new state_.

`dispatch({ type: REMOVE_TODO, id });`

When someone **clicks on ✓** then _dispatch function_ will trigger _reducer_ with action type _COMPLETE_TODO_, then reducer will _update_ that object based on _id_ and return _new state_.

`dispatch({ type: COMPLETE_TODO, id });`


Let's put some _CSS_ in _index.css_ file,

```
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
    sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
    monospace;
}

.App {
  width: 205px;
  margin: auto;
}

.todoItem {
  width: 100%;
  float: left;
  border-bottom: 1px solid;
}

.todoItem p {
  float: left;
}

.actionType {
  float: right;
  margin-top: 15px;
}
```

If you want to download the full demo project then click here [Demo git](https://github.com/abdullahmubin/useReducer).

That's all for today, next, we will learn about react **useContext** hook and how to use with **useReducer**.

See ya.