Skill: Manage Complex State with useReducer
Instead of juggling multiple useState calls, you can use useReducer to handle state transitions in a more structured way, similar to how Redux works.
When to Use useReducer
When your state has multiple interdependent variables (e.g., a form or a complex UI).
When your state transitions are complex and involve multiple actions.
When you want a cleaner and more scalable state management solution.
Example: Managing a Complex Form
Let’s use useReducer to handle the state of a form with multiple fields and actions:
import React, { useReducer } from "react"; // Define initial state const initialState = { username: "", email: "", password: "", isSubmitting: false, error: null, }; // Define a reducer function const formReducer = (state, action) => { switch (action.type) { case "SET_FIELD": return { ...state, [action.field]: action.value }; case "SUBMIT_START": return { ...state, isSubmitting: true, error: null }; case "SUBMIT_SUCCESS": return { ...initialState }; // Reset form on success case "SUBMIT_ERROR": return { ...state, isSubmitting: false, error: action.error }; default: throw new Error(`Unknown action type: ${action.type}`); } }; const ComplexForm = () => { // Use useReducer to manage form state const [state, dispatch] = useReducer(formReducer, initialState); const handleChange = (e) => { const { name, value } = e.target; dispatch({ type: "SET_FIELD", field: name, value }); }; const handleSubmit = async (e) => { e.preventDefault(); dispatch({ type: "SUBMIT_START" }); try { // Simulate form submission await new Promise((resolve) => setTimeout(resolve, 1000)); console.log("Form submitted:", state); dispatch({ type: "SUBMIT_SUCCESS" }); } catch (error) { dispatch({ type: "SUBMIT_ERROR", error: "Submission failed!" }); } }; return ( <form onSubmit={handleSubmit}> <div> <label>Username:</label> <input name="username" value={state.username} onChange={handleChange} /> </div> <div> <label>Email:</label> <input name="email" value={state.email} onChange={handleChange} /> </div> <div> <label>Password:</label> <input name="password" type="password" value={state.password} onChange={handleChange} /> </div> {state.error && <p style={{ color: "red" }}>{state.error}</p>} <button type="submit" disabled={state.isSubmitting}> {state.isSubmitting ? "Submitting..." : "Submit"} </button> </form> ); }; export default ComplexForm; How It Works
- State Centralization:
- All form fields, submission state, and error handling are managed in a single state object.
- Reducer Logic:
Actions (SET_FIELD, SUBMIT_START, etc.) describe what happens.
The reducer updates the state based on these actions.
- Form Submission:
- On form submission, the state transitions smoothly through SUBMIT_START, SUBMIT_SUCCESS, or SUBMIT_ERROR.
Why Use This?
Scalability: Adding more fields or actions (like reset) is straightforward.
Readability: State transitions are centralized and predictable.
Performance: State updates are handled in bulk, reducing re-renders compared to multiple useState calls.
This skill is invaluable for managing complex state logic and making your React components more robust!
Top comments (0)