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)