LogoTRUONG PHAM
Home
Projects
Blogs
YouTube
Contact

Newsletter

Stay updated with technical artifacts and engineering insights.

LogoTRUONG PHAM

Building scalable software and sharing insights on technology & life.

Sitemap

  • Home
  • Projects
  • Blogs
  • YouTube
  • Contact

Connect

  • GitHub
  • LinkedIn
  • Email
  • YouTube

© 2024 TRUONG PHAM. © All rights reserved.

Privacy PolicyTerms of Service
Back
Blog #30: A giant State Object doesn't make your code cleaner
50 FRONTEND LESSONS – HARD-EARNED EXPERIENCES

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.

TP
Truong PhamSoftware Engineer
PublishedJune 20, 2024

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 useEffect to 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 useEffect effectively, 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, y coordinates 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

50 FRONTEND LESSONS – HARD-EARNED EXPERIENCES

NextBlog #31: 1 AM and the Search for the 'Missing' File
Blog #29: When 'Controlled Component' turns into a performance burden
25Blog #25: Context API Perf Hit – When the 'standard React' solution betrays you26Blog #26: Don't let 'Single Source of Truth' become blind dogma27Blog #27: useEffect is not the place for doing all synchronizing logic28Blog #28: The naivety of believing setState is an immediate assignment29Blog #29: When 'Controlled Component' turns into a performance burden30Blog #30: A giant State Object doesn't make your code cleanerReading31Blog #31: 1 AM and the Search for the 'Missing' File32Blog #32: Friday Afternoon, 800 Lines of Code, and a Miscalculation33Blog #33: 10 PM and the 'Infinite Loop' of Punishment34Blog #34: My Machine Runs Smooth, the User's Machine Smokes35Blog #35: Clean Architecture – The Dream and the Harsh Reality
TP

Written by Truong Pham

Software Engineer passionate about building high-performance systems and meaningful experiences.

Read more articles