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 #14: The Domino Effect – When one small change crashes the whole Render system
50 FRONTEND LESSONS – HARD-EARNED EXPERIENCES

Blog #14: The Domino Effect – When one small change crashes the whole Render system

To my early React days, when I wondered why changing one text color made the whole 1000-row table redraw from scratch.

TP
Truong PhamSoftware Engineer
PublishedApril 18, 2024

Hey there,

I remember how frustrated you were. You had a complex Dashboard with many child components. You just wanted to add a tiny countdown clock in the corner of the screen. You created a seconds state in the parent component (App), and every second you called setSeconds.

The result? Every second, the entire chart, data table, and user list... everything gave a "slight stutter." Typing in the search bar suddenly felt laggy. You panicked: "Why is React so slow?". You had no idea you'd accidentally triggered an unnecessary "general mobilization" re-render on an application-wide scale.

1. Simple Explanation: The Story of a Family

Imagine a 3-generation family living together. You are the father (Root Component). The supervisor is the grandfather. Your children are the child UIs. Every second, you stand in the middle of the house and shout: "It's now the 32nd second!".

As soon as you shout, everyone in the house—no matter what they're busy doing—must stop, look at you, self-check if the "32nd second" information relates to them, and then continue working. If you shout every second, everyone will go crazy and no one will get anything done properly.

2. Current Perspective: Why 'State Placement' matters?

Before, you thought "if there's data, just push it up to the parent for easy management." But now I understand: The closer the state is to where it's used, the smoother the app. React is incredibly fast, but comparing the Virtual DOM for thousands of child components every second is a massive waste of resources. When you change state in a Parent Component, by default, all its Child Components must re-render (unless you use memo, but that's a different story about costs we discussed in article #13).

3. Concrete Example: The "Global State" Trap

You used to do this because it was "convenient":

// Junior's way: "Top floor" holds everything
const Dashboard = () => {
  const [timer, setTimer] = useState(0); // State changes constantly
  const [data, setData] = useState([]); // Heavy data

  useEffect(() => {
    const id = setInterval(() => setTimer(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);

  return (
    <div>
      <TimerDisplay time={timer} />
      {/* 
        Every time timer changes, BigExpensiveChart will re-render 
        even though data hasn't changed! 
      */}
      <BigExpensiveChart data={data} />
    </div>
  );
};

Why is this a problem? Because BigExpensiveChart must redo its chart calculation logic once every second. If the user's machine is weak, they'll see the browser freeze continuously.

Sustainable Approach (State Colocation):

// Push state as low as possible
const Timer = () => {
  const [timer, setTimer] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setTimer(t => t + 1), 1000);
    return () => clearInterval(id);
  }, []);
  return <TimerDisplay time={timer} />;
};

const Dashboard = () => {
  const [data, setData] = useState([]);
  
  return (
    <div>
      <Timer /> {/* Only Timer re-renders every second, Dashboard and Chart stay still! */}
      <BigExpensiveChart data={data} />
    </div>
  );
};

4. Comparison: "Doing it Fast" vs "Doing it Sustainably"

CriteriaDoing it Fast (Push it all to Parent)Doing it Sustainably (State Colocation)
Data ManagementVery easy, everything is available at parentTakes effort to think about where state should be
Render PerformanceDisaster as the app growsAbsolutely optimized, isolated renders
DebuggingHard to find what causes re-rendersEasy to isolate errors in small components
MindsetMonolithic "monster" styleAtomic style

Juniors often choose the left column because "it's tedious to pass props." But a Senior will choose the right column because they respect every CPU cycle of the user's computer.

5. Practical Lesson: "Meaningless" Render

I once encountered a bug where when a user typed into an Input in the Header, a list of 500 articles in the Body would lag. It turned out that Input was changing a state at a Context Provider wrapped around the entire application. The whole app was "shaking" every time the user typed a character.

The biggest lesson is: Keep state in the smallest cage possible. If a state only serves one component, never let it escape. "Lift state up" only when you really need to share data between siblings; don't do it out of laziness.

Remember: A smooth application isn't because it uses cool libraries, but because its hundreds of child components know when to "be quiet" and stay still.


Notes for my 25-year-old self, back when I learned to 'restrain' re-renders.

Series • Part 14 of 50

50 FRONTEND LESSONS – HARD-EARNED EXPERIENCES

NextBlog #15: The 10,000-Row Lesson – When Table Virtualization saved my career
Blog #13: When optimization becomes a burden – Don't 'memo' everything you see
09Blog #9: Safari – The new 'Internet Explorer' of the modern era?10Blog #10: Specificity War – When !important marks the start of a civil war11Blog #11: Don't wait until 'heavy web' to lose weight for your Bundle12Blog #12: Don't bring the whole supermarket home just to buy a loaf of bread13Blog #13: When optimization becomes a burden – Don't 'memo' everything you see14Blog #14: The Domino Effect – When one small change crashes the whole Render systemReading15Blog #15: The 10,000-Row Lesson – When Table Virtualization saved my career16Blog #16: Misplaced Debounce – When a localized solution becomes a system burden17Blog #17: Images vs JS – The battle for priority in the Critical Path18Blog #18: Laggy Animations – When the touch is no longer smooth19Blog #19: Chrome Performance Tab – Looking through a microscope at the system's pulse
TP

Written by Truong Pham

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

Read more articles