Using useReducer for Complex State Logic
2 min readDec 15, 2024
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
- Actions (SET_FIELD, SUBMIT_START, etc.) describe what happens.
- The reducer updates the state based on these actions.
Why Use This?
This skill is invaluable for managing complex state logic and making your React components more robust!
Originally published at https://remejuan.substack.com.