Introduction
The useReducer()
hook is used to manage the state of a component. It's an alternative to the useState() hook.
The useReducer()
can handle complex state logic more elegantly than useState(). It separates the state manipulation logic from the component and this makes the component less verbose and lighter.
Syntex
import {useReducer} from 'react';
function Counter(){
const [state, dispatch] = useReducer(reducerFn, initialState);
// ....
}
Returned Value
The useReducer()
returns an array with two values:
state: It represents the state value.
dispatch function: It's a function that we call when we need to update the state. It takes an action object as an argument. The action object describes what action we want to perform on the state, like a decrement or increment of the count value.
const increment = () => { dispatch({ type: 'INCREMENT' }); };
Arguments
The useReducer
takes two arguments:
reducerFn: This is the function that contains the state updation logic. It accepts two parameters: state
and action
. Based on the action type it updates the state.
// Reducer function
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
case 'RESET':
return { count: 0 };
default:
return state;
}
};
When we dispatch an action, the reducer function is called with the current state and the action. It determines the new state based on the action type and returns the updated state.
The reducer function updates state in immutable manner. If we try to update state directly, React may not be able to detect changes and won't re-render the component.
InitialState: It represents the initial value of the state.
//... const initialState = { count: 0 }; function Counter(){ const [state, dispatch] = useReducer(reducerFn, initialState); // .... }
Example
import React, { useReducer } from 'react';
// Reducer function
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
case 'RESET':
return { count: 0 };
default:
return state;
}
};
const Counter = () => {
// Initialize state using useReducer
const [state, dispatch] = useReducer(reducer, { count: 0 });
// Event handlers
const increment = () => {
dispatch({ type: 'INCREMENT' });
};
const decrement = () => {
dispatch({ type: 'DECREMENT' });
};
const reset = () => {
dispatch({ type: 'RESET' });
};
return (
<div>
<h1>Count: {state.count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
<button onClick={reset}>Reset</button>
</div>
);
};
export default Counter;
In this example, we have a simple Counter
component. The reducer function defines the state transitions based on the action type provided. The initial state is { count: 0 }
.
To update states, we have defined event handlers,(increment
, decrement
, and reset
) that dispatch actions to the reducer based on user interactions.
When an action is dispatched, the reducer
function is called with the current state and the action. It determines the new state based on the action type and returns the updated state.
Conclusion
The useReducer(reducer, initialState)
hook is used to manage complex states and helps to write the state updation logic separately.
We use the dispatch(action)
function to update the state and the reducer(state, action)
function updates the state based on the action type.