Mahamudul Hasan Rubel
HomeAboutProjectsSkillsExperienceBlogPhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • About
  • Projects
  • Skills
  • Experience
  • Blog
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
ReactNext.jsJune 22, 20264 min read

React reconciliation and component state persistence: A mental model

React reconciliation determines how component state persistence works during re-renders. Learn how React Fiber maintains your UI state across cycles.

ReactFrontend EngineeringWeb DevelopmentJavaScriptReconciliationNext.jsTutorial

I remember the first time I built a form in React that kept wiping its own input fields whenever the parent component re-rendered. I spent about three hours digging through documentation, convinced I’d found a bug in the library itself. It turned out I was just breaking the component's stable identity.

If you’ve ever felt like your state is "disappearing" for no reason, you’re likely fighting against how React manages the tree. Understanding how React reconciliation works isn't just an academic exercise; it's the difference between a smooth user experience and a buggy, flickering interface.

The "Stable Identity" Mental Model

When you write JSX, you're describing a tree. React doesn't just render this tree once; it constantly compares the new tree you provide against the one currently in the browser. This process, often powered by the React Fiber architecture, is how React decides what to keep and what to destroy.

Think of React as a very diligent, slightly literal-minded librarian. When a component re-renders, React walks the tree. If it sees the same component type at the same position in the tree, it assumes it's the same instance. It keeps the state, the hooks, and the DOM nodes. If the position changes or the component type switches, it tears everything down and starts from scratch.

This is the core of component state persistence. If you define a component inside another component’s render function, you are effectively telling React: "This is a brand new component every single time."

JSX
function Parent() {
  // DON'T DO THIS
  function Child() {
    const [count, setCount] = useState(0);
    return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
  }

  return <Child />;
}

In the code above, every time Parent re-renders, Child is redefined. React sees a different function reference, assumes the tree has changed, destroys the old Child, and mounts a new one. Your count state? It’s gone. You’ve broken the stable identity.

Why Reconciliation Matters

We often talk about the virtual DOM as a performance optimization, but its real job is maintaining the relationship between your code and the browser's reality. When React keys and reconciliation: Why stable identity matters, we are essentially giving React a way to track identity even when the order of elements changes.

Without keys, or by using unstable ones like array indices, React gets confused. It tries to guess if an item moved or was replaced. If it guesses wrong, you get UI bugs—like a checkbox that stays checked when you filter a list, or an input field that keeps focus on the wrong element.

I once worked on a dashboard where we were using Math.random() for keys. It was a disaster. Around 280ms of latency was added to every update because React was essentially throwing away the entire DOM tree and rebuilding it from scratch every time the state updated. It was a heavy, unnecessary cost.

How to Keep Your State Alive

If you want to preserve state during a render cycle, follow these three rules:

  1. Hoisting: Never define a component inside another component. Move it out to the top level or a separate file.
  2. Stable Keys: If you’re rendering lists, use a unique ID from your data (like a database UUID) rather than the array index.
  3. Identity Stability: If you need to "reset" a component's state, use the key prop explicitly. Changing the key tells React: "This is officially a new instance, please wipe the old state."

This is also a major factor when working with Next.js Server Components hydration. When the server sends HTML and the client tries to hydrate it, if the tree structure doesn't match perfectly, React will often dump the server-rendered content and re-render everything to be safe. It’s a silent performance killer.

A Quick Reality Check

Sometimes, we over-engineer this. I’ve seen developers spend days wrapping components in useMemo or memo to prevent re-renders, only to realize the re-render wasn't the performance bottleneck—it was the reconciliation logic itself.

Before you start memoizing everything, ask yourself: is the component's identity stable? If the parent re-renders, does the child stay in the same place in the tree?

I’m still not 100% sure if the upcoming React compiler will fully eliminate the need for us to worry about these manual identity patterns. My guess? It will handle the boring stuff, but understanding the underlying tree structure will remain a superpower for when things inevitably get complex. Don't worry about being perfect; just focus on keeping your references stable and your keys unique.

FAQ

Does changing a component's key always destroy state? Yes. When the key prop changes, React treats it as a completely different component instance and triggers a full unmount and remount.

Why does using an index as a key cause issues? If you reorder the list, the index of an item changes. React looks at the new tree, sees an item at index 0, and assumes it’s the same one that was at index 0 before, even if the data inside has changed. This leads to state mismatches.

Is it okay to define helper functions inside a component? Yes, that's fine. The problem is specifically defining components (functions that return JSX) inside other components.

Back to Blog

Similar Posts

Close-up of JavaScript code on a laptop screen, showcasing programming in progress.
ReactNext.jsJune 20, 20264 min read

React State Management: How to Lift State Up Effectively

React state management gets easier when you learn how to lift state up. Discover how to sync sibling components and build a predictable data flow today.

Read more
React
Next.js
June 22, 2026
4 min read

Next.js Hydration Mismatch: Why Components Render Twice and Syncing Fixes

Next.js hydration errors happen when the server and client disagree. Learn how to debug React hydration mismatch and sync your components for faster apps.

Read more
ReactNext.jsJune 22, 20264 min read

React useEffect: A Synchronization Tool, Not State Management

React useEffect is for synchronizing external systems, not state management. Learn why treating it as a lifecycle method leads to bugs and how to fix it.

Read more