- Published on
How to Use React useReducer() Hook
In this article we are going to explore useReducer
Hook in react which is one of the most usefull hook that is used to manage complex state logic in react.
What is useReducer?
State updates are crucial part for implementing any feature in React. They allow you manage and modify the data that drives your application's functionality. If you are alredy familiar with react you know that useState
is one of the most common ways to manage state just like the useState
hook in react useReducer
is also used to manage state it is an alternative to useState
that is best suited for managing state in more complex scenarios.
Syntax:
const [state, dispatch] = useReducer(reducer, initialState);
state
variable holds the current state valuedispatch
is a function that allows us to send actions to the reducer.reducer
function is responsible for updating the state based on the dispatched actioninitialState
represents the initial value of the state.
Let's start with a simple counter example to understand the basic usage of useReducer:
Let's start define the initial state for the counter with single property count
initialized with a value of 0.
const initialState = { count: 0 }
Next we will create our reducer as we mentioned above The reducer takes two parameters: state
and action
and it is responsible for updating the state based on the action type.
const reducer = (state, action) => {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
default:
throw new Error()
}
}
In the above reducer we have two action types
increment
responsible for incrementing the count by 1 and It return a new state objectdecrement
responsible for decrementing the count by 1 and It return a new state object
We also added a default case for handling any unknown action type. The default case throws an error to indicate an invalid action type.
Let's now create the Counter
component and use our reducer
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState)
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
)
}
In the above program we are using useReducer
hook to manage the state. we passed the initial state and the reducer as arguments and and we distructor the current state and a dispatch function.
Now, let's explore a more complex example of a todo list using useReducer:
import React, { useReducer, useState } from 'react'
const initialState = {
todos: [],
}
const reducer = (state, action) => {
switch (action.type) {
case 'add':
return { todos: [...state.todos, action.payload] }
case 'toggle':
return {
todos: state.todos.map((todo) =>
todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo
),
}
case 'delete':
return {
todos: state.todos.filter((todo) => todo.id !== action.payload),
}
default:
throw new Error()
}
}
const TodoForm = ({ onAddTodo }) => {
const [text, setText] = useState('')
const handleChange = (e) => {
setText(e.target.value)
}
const handleSubmit = (e) => {
e.preventDefault()
if (!text.trim()) return
onAddTodo({
id: Math.random(),
text: text,
completed: false,
})
setText('')
}
return (
<form onSubmit={handleSubmit}>
<input type="text" value={text} onChange={handleChange} />
<button type="submit">Add Todo</button>
</form>
)
}
const Todo = ({ todo, onToggleTodo, onDeleteTodo }) => {
const handleToggle = () => {
onToggleTodo(todo.id)
}
const handleDelete = () => {
onDeleteTodo(todo.id)
}
return (
<div>
<input type="checkbox" checked={todo.completed} onChange={handleToggle} />
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>{todo.text}</span>
<button onClick={handleDelete}>Delete</button>
</div>
)
}
const TodoList = () => {
const [state, dispatch] = useReducer(reducer, initialState)
const handleAddTodo = (todo) => {
dispatch({ type: 'add', payload: todo })
}
const handleToggleTodo = (id) => {
dispatch({ type: 'toggle', payload: id })
}
const handleDeleteTodo = (id) => {
dispatch({ type: 'delete', payload: id })
}
return (
<div>
<TodoForm onAddTodo={handleAddTodo} />
{state.todos.map((todo) => (
<Todo
key={todo.id}
todo={todo}
onToggleTodo={handleToggleTodo}
onDeleteTodo={handleDeleteTodo}
/>
))}
</div>
)
}
Conclusion
React's useReducer hook is a powerful tool for managing state in functional components. It provides a way to handle complex state logic by utilizing a reducer function. In this article, we explored the basics of useReducer with the help of an example to illustrate its usage and benefits. After reading this article, I hope you feel confident about using useReducer
hook in you react project. Happy coding!