Last Updated on June 17, 2024
import {useReducer} from "react"; interface CounterAction { type: CounterType, data: number } enum CounterType { INCREASE, DECREASE } interface CounterState { count: number } function CounterReducer(state: CounterState, action: CounterAction): CounterState { if (action.type === CounterType.INCREASE) { return {...state, count: state.count + action.data} } else if (action.type === CounterType.DECREASE) { return {...state, count: state.count - action.data} } return {...state}; } function Counter() { // initial value for counter const counterInitializerArg: CounterState = {count: 0}; // counter value let counterState: CounterState; // this is a function with CounterAction as parameter, it will increase/decrease counter value by 1 let counterDispatch: (payload: CounterAction) => void; [counterState, counterDispatch] = useReducer(CounterReducer, counterInitializerArg); return ( <> <div> Count : {counterState.count} </div> <div> <button type="button" className="btn" onClick={event => counterDispatch({type: CounterType.INCREASE, data: 1})}>Increase </button> <button type="button" className="btn" onClick={event => counterDispatch({type: CounterType.DECREASE, data: 1})}>Decrease </button> </div> </> ); } export default Counter;
Specifying the initial state
There are two different ways to initialize useReducer
state. You may choose either one depending on the use case. The simplest way is to pass the initial state as a second argument:
const [state, dispatch] = useReducer( reducer, {count: initialCount} );
Lazy initialization
You can also create the initial state lazily. To do this, you can pass an init
function as the third argument. The initial state will be set to init(initialArg)
.
It lets you extract the logic for calculating the initial state outside the reducer. This is also handy for resetting the state later in response to an action:
function init(initialCount) { return {count: initialCount}; } function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; case 'reset': return init(action.payload); default: throw new Error(); } } function Counter({initialCount}) { const [state, dispatch] = useReducer(reducer, initialCount, init); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset </button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }
References
https://reactjs.org/docs/hooks-reference.html#usereducer
https://dev.to/craigaholliday/using-the-usereducer-hook-in-react-with-typescript-27m1