What is useReducer?
useReducer
is like useState
, but it’s better when:
- State has multiple sub-values
- You want to centralize logic (like in Redux)
- You need predictable state updates
✅ Syntax
const [state, dispatch] = useReducer(reducer, initialState);
– reducer
= a function that receives current state + action → returns new state
– dispatch(action)
= used to trigger state updates
🧪 Simple Counter Example with useReducer
import React, { useReducer } from "react";
// Step 1: Reducer function
function 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;
}
}
// Step 2: Initial state
const initialState = { count: 0 };
function Counter() {
// Step 3: useReducer
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div style={{ padding: "20px" }}>
<h2>Count: {state.count}</h2>
<button onClick={() => dispatch({ type: "increment" })}>+1</button>
<button onClick={() => dispatch({ type: "decrement" })}>-1</button>
<button onClick={() => dispatch({ type: "reset" })}>Reset</button>
</div>
);
}
export default Counter;
🧠 Why Use useReducer
Over useState
?
Scenario | useState | useReducer |
---|---|---|
Simple toggle | ✅ | ❌ |
Counter | ✅ | ✅ |
Form with multiple fields | 👎 messy | ✅ better |
Centralized logic | ❌ | ✅ |
Multiple conditions or steps | ❌ | ✅ |
🛠 You Can Use Objects or Strings for Action
Example:
dispatch({ type: "increment" }); // object
dispatch("increment"); // possible with custom reducer
Multi-field form using useReducer
import React, { useReducer } from "react";
// Step 1: Initial form state
const initialState = {
name: "",
email: "",
age: "",
};
// Step 2: Reducer function
function formReducer(state, action) {
switch (action.type) {
case "UPDATE_FIELD":
return {
...state,
[action.field]: action.value,
};
case "RESET":
return initialState;
default:
return state;
}
}
function FormWithReducer() {
// Step 3: Setup useReducer
const [formState, dispatch] = useReducer(formReducer, initialState);
// Step 4: Handle input change
const handleChange = (e) => {
const { name, value } = e.target;
dispatch({
type: "UPDATE_FIELD",
field: name,
value: value,
});
};
// Step 5: Handle submit
const handleSubmit = (e) => {
e.preventDefault();
console.log("Form submitted:", formState);
alert("Check console for submitted data.");
};
return (
<div style={{ padding: "20px" }}>
<h2>Form using useReducer</h2>
<form onSubmit={handleSubmit}>
<div>
<label>Name: </label>
<input
name="name"
value={formState.name}
onChange={handleChange}
required
/>
</div>
<div>
<label>Email: </label>
<input
name="email"
value={formState.email}
onChange={handleChange}
required
/>
</div>
<div>
<label>Age: </label>
<input
name="age"
type="number"
value={formState.age}
onChange={handleChange}
/>
</div>
<br />
<button type="submit">Submit</button>
<button type="button" onClick={() => dispatch({ type: "RESET" })}>
Reset
</button>
</form>
</div>
);
}
export default FormWithReducer;
Keep Learning 🙂