Blog #30: A giant State Object doesn't make your code cleaner
I once thought merging all states into one object const [form, setForm] = useState(...) was professional. I was wrong.
I admit I once had a strong belief in "tidiness." When seeing someone write 5-6 consecutive lines of useState in a component, I would often sneer: "Why not group them into an Object for neatness?". I believed that a single useState for the entire component was the way of system-thinking programmers.
I believed it because it looked very similar to working with this.state in old Class Components. It gave a sense of easy management and easy prop passing to child components. But reality proved otherwise when the project started to grow and needed maintenance.
1. Context: The "Grouping" Trap
I built a User Profile configuration page. Instead of separating each information piece, I created a userProfile variable containing all: name, email, avatar, jobTitle, skills, interests, socialLinks...
The consequences:
- Extremely tiring updates: Every time I wanted to change the
email, I had to write:setProfile(prev => ({ ...prev, email: newValue })). Thus, my code was flooded with...spread operators. - Re-render Leaks: Even if a child component only needed to display
name, it was forced to depend on the whole giant object. - Dependency Hell: When using
useEffectto observe that object, it would always re-run for every tiny change, unless I wrote complex comparisons.
2. Concept: Atomic State
The problem was I sacrificed logic simplicity just for the appearance of neatness. React Hooks was designed for an "atomic" direction, where each state variable should represent an independent piece of information.
// How I used to do it (Sounds "neat" but is troublesome)
const [state, setState] = useState({ name: '', age: 0, loading: false });
// Practical way (Clear and easy to use)
const [name, setName] = useState('');
const [age, setAge] = useState(0);
const [isLoading, setIsLoading] = useState(false);
3. Practical Approach and Balance
A Junior will often copy this "object merging" style from old projects or from Class Component experience. They think many lines of useState is a sign of "novice" code.
Comparison of two ways:
- Object Merging: Looks neat but updating code is troublesome, hard to use
useEffecteffectively, easily causes errors when forgetting the...symbol. - Atomic Separation: Might take a few extra lines of declaration but extremely easy to manage. Want to change the email?
setEmail(val). Done. No fear of affecting anyone else.
Lesson Learned
I learned that: Visual tidiness is not as valuable as logical clarity.
- When the old way (Object Merging) is still correct: When data fields always change together and are closely related logically (e.g.,
x,ycoordinates of the mouse cursor). - When to avoid: Avoid merging unrelated data into the same object just "to look good."
Let your code "breathe" by separating states. Don't force them to live under the same roof when they have nothing in common.
Notes on the day I learned the power of small independent things.
Series • Part 30 of 50