PresentationInteractive, narrated presentation of the section content.
ContentDetailed description of the section content.
The useReducer hook is an alternative to useState for managing state in React functional components. It is particularly useful for complex state logic involving multiple sub-states or when the next state depends on the previous state.
Key Differences Between useState and useReducer
| Feature | useState | useReducer |
|---|---|---|
| Complexity | Ideal for simple state logic | Suitable for complex state logic |
| State Updates | Directly set state via updater | Use a reducer function to determine state changes |
| Structure | Single piece of state | State + Dispatch + Reducer Function |
| Scalability | Can become messy with multiple states | Organizes updates into a single function |
When to Use useReducer Over useState
- When state logic is complex or interdependent.
- When state updates involve multiple actions.
- When you need a clean way to handle state transitions (like in a finite state machine).
Example: From useState to useReducer
Let’s refactor an example where a simple word counter with delete and reset actions evolves from useState to useReducer.
Step 1: Using useState
Here’s a counter example with useState:
import React, { render, useState } from "react";
const CounterWithState = () => {
const [count, setCount] = useState(0);
const [word, setWord] = useState("");
function changeHandler(e) {
setWord(e.currentTarget.value);
setCount(e.currentTarget.value.length);
}
function del() {
if (word.length) {
setWord(word.slice(0, -1));
setCount(count - 1);
}
}
function reset() {
setWord("");
setCount(0)
}
return (
<div>
<h1>Counter with useState</h1>
<p>Letters: {count}</p>
<input value={word} onChange={changeHandler} />
<button onClick={del}>Delete</button>
<button onClick={reset}>Reset</button>
</div>
);
};
render(<CounterWithState />)
Step 2: Refactor to useReducer
Here, we replace useState with useReducer for a cleaner and more scalable approach.
1. Define the Reducer Function
The reducer function determines how state changes based on an action.
type State = {
word: string,
count: number
}
type Action =
| { type: 'WORD', value: string }
| { type: 'DELETE' }
| { type: 'RESET' }
const reducer = (state: State, action: Action) => {
switch (action.type) {
case "WORD":
return { count: action.value.length, word: action.value };
case "DELETE":
return state.word.length
? { count: state.count - 1, word: state.word.splice(0, -1) }
: state;
case "RESET":
return { word: '', count: 0 };
default:
throw new Error("Action not handled");
}
};
2. Implement the Component
Here’s the updated counter using useReducer:
Copy code
import React, { useReducer } from "react";
const CounterWithReducer = () => {
const [state, dispatch] = useReducer(reducer, { count: 0, word: "" });
return (
<div>
<h1>Counter with useState</h1>
<p>Letters: {state.count}</p>
<input value={state.word} onChange={(e) => dispatch('WORD', e.currentTarget.value)} />
<button onClick={() => dispatch('DELETE')}>Delete</button>
<button onClick={() => dispatch('RESET')}>Reset</button>
</div>
);
};
export default CounterWithReducer;
How It Works:
- Reducer Function: Handles all state transitions based on the action's
type. - Initial State:
{ count: 0, word: “” }is passed as the initial state touseReducer. - Dispatch: Instead of calling
setState, we calldispatchwith anactionobject.
Advantages of useReducer Over useState:
- Cleaner state management for complex logic.
- Centralized state transitions in a single
reducerfunction. - Easier to debug and test state logic.
- Scalability when adding more actions or state properties.
- Easier to test independently on React
Example Comparison: Before and After
| Feature | useState Example | useReducer Example |
|---|---|---|
| State Structure | Single state variable | Centralized state object |
| Update Logic | Spread across multiple setState calls | Encapsulated in the reducer function |
| State Updates | Direct calls to setState | dispatch triggers state updates |
Conclusion
useStateis great for simple scenarios with minimal state logic.useReduceris a powerful tool for managing complex state logic and actions.
This refactoring demonstrates how useReducer provides better structure, cleaner code, and enhanced scalability for complex state management. Let me know if you'd like a more advanced example! 🚀
No hints available.