Skip to content

Commit 8a0c79b

Browse files
committed
changed header structure
1 parent d2efed1 commit 8a0c79b

1 file changed

Lines changed: 19 additions & 19 deletions

File tree

blog-posts/en/react-performance-and-preventing-unnecessary-re-renders.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Re-rendering in React is not a flaw; it is the framework's fundamental operating
1111

1212
In this article, we will explore React's re-render mechanism, uncover the root causes of unnecessary re-renders, and detail the architectural principles essential for sustaining high performance in large-scale applications.
1313

14-
# What Does "Re-rendering" Actually Mean in React?
14+
## What Does "Re-rendering" Actually Mean in React?
1515

1616
When a component renders in React, the DOM is not directly rebuilt from scratch. Instead, the following sequence of events occurs:
1717

@@ -29,7 +29,7 @@ While React is highly efficient at minimizing actual DOM manipulations, the re-e
2929

3030
Therefore, the primary goal of React performance optimization is not to manage the DOM, but to reduce unnecessary component executions.
3131

32-
# Why Do React Components Re-render?
32+
## Why Do React Components Re-render?
3333

3434
React operates on a declarative model. It inherently assumes that the UI is always a direct reflection of the state. Because of this, when a parent component renders, React’s default behavior is to re-execute all of its child components.
3535

@@ -58,7 +58,7 @@ In this scenario, `HeavyComponent` doesn't use the `count` state at all. However
5858

5959
![Parent State Change Child Render](/Images/Blog/parent-state-change-child-render.gif)
6060

61-
# The Most Critical Performance Principle: State Locality
61+
## The Most Critical Performance Principle: State Locality
6262

6363
When faced with re-render problems like the one above, a developer's first reflex is usually to sprinkle `useMemo` or `React.memo` everywhere. However, there is a much simpler and far more effective solution: **State Locality** (also known as State Colocation).
6464

@@ -96,7 +96,7 @@ Now, when the button is clicked, the only thing that changes is the internal wor
9696

9797
This architectural principle teaches us a golden rule: The best way to prevent unnecessary re-renders is not memoization, but rather physically blocking the spread of the re-render wave by breaking components down into logical, isolated pieces.
9898

99-
# What Does React.memo Actually Do? (A Shield Against Unnecessary Renders)
99+
## What Does React.memo Actually Do? (A Shield Against Unnecessary Renders)
100100

101101
At its core, `React.memo` is a filter that prevents your component from rendering unnecessarily. It adds a simple validation step to the normal React flow.
102102

@@ -127,15 +127,15 @@ Wrapping every single component in `React.memo` is an anti-pattern. The checking
127127
* **Large lists:** Lists containing thousands of rows of data.
128128
* **Heavy UI elements:** Charts, interactive maps, complex data tables, and dashboard components.
129129

130-
## A Small Detail (And a Big Danger): Shallow Comparison
130+
### A Small Detail (And a Big Danger): Shallow Comparison
131131

132132
There is a critical point here that requires careful attention: `React.memo` does not perform a deep analysis. It uses a method called **shallow comparison**.
133133

134134
This means `React.memo` only checks for referential equality. If you pass an object, array, or function as a prop to the component, and these references are re-created on every render, `React.memo` gets bypassed and loses its shielding capability.
135135

136136
This is exactly why **Referential Stability** is of paramount importance for `React.memo` to function as intended.
137137

138-
# The Most Common Performance Issue: Referential Instability
138+
## The Most Common Performance Issue: Referential Instability
139139

140140
In JavaScript, primitive types like `string` or `number` are compared by their values, whereas objects, arrays, and functions are reference types. This means they are compared by their memory addresses (locations).
141141

@@ -148,7 +148,7 @@ This implies that two completely identical objects are not equal to each other i
148148

149149
This is exactly the limitation of the shallow comparison mechanism used by `React.memo`. React looks at the memory references of objects or functions, not their actual contents.
150150

151-
## A Problematic Approach
151+
### A Problematic Approach
152152

153153
In the example below, a new object is directly defined for the `config` prop every time the parent component renders. Even though its content is always `{ theme: "dark" }`, its reference constantly changes because a brand new object is created in memory each time.
154154

@@ -160,7 +160,7 @@ In the example below, a new object is directly defined for the `config` prop eve
160160

161161
Even if you wrapped the `Child` component with `React.memo`, React would see that the incoming memory address for the prop has changed. Assuming the props have been updated, it will unnecessarily re-execute the component.
162162

163-
## Stabilizing References
163+
### Stabilizing References
164164

165165
To solve this, we need to keep the reference of the object or function stable throughout the component's lifecycle. For objects and arrays, we can use the `useMemo` hook:
166166

@@ -188,7 +188,7 @@ const handleClick = useCallback(() => {
188188

189189
In summary, `useMemo` and `useCallback` are the most common tools used to stabilize references inside React components, ensuring `React.memo` works correctly and efficiently. However, it should be noted that these hooks provide a genuine performance boost primarily when used to stabilize values passed as props to child components wrapped in `React.memo`.
190190

191-
# The Real Performance Bottleneck: Component Execution Cost
191+
## The Real Performance Bottleneck: Component Execution Cost
192192

193193
In React applications, the source of performance issues is rarely DOM updates, contrary to popular belief. Modern browsers and React's internal optimization algorithms handle DOM manipulations quite efficiently.
194194

@@ -205,15 +205,15 @@ Real performance costs typically stem from the following:
205205

206206
Imagine displaying a table or list with 1,000 rows. If an unrelated state change in a parent component triggers a re-render of this list, the browser spends significant CPU power processing those 1,000 elements even if React ultimately decides that nothing in the actual DOM needs to change.
207207

208-
## The Solution: Virtualization
208+
### The Solution: Virtualization
209209

210210
When rendering massive data lists, `React.memo` alone isn't enough. In these cases, the essential architectural approach is **Virtualization**.
211211

212212
Libraries like `react-window` or `react-virtuoso` avoid adding thousands of nodes to the DOM. Instead, they only render the elements currently visible within the user's **viewport**.
213213

214214
As the user scrolls, new DOM elements aren't necessarily created; instead, existing DOM nodes are recycled and updated with new data. This approach shifts the rendering cost from $O(n)$ (relative to the total data size) down to roughly $O(\text{visible})$ dramatically reducing both DOM size and component execution overhead.
215215

216-
# The Hidden Performance Risk of Context API
216+
## The Hidden Performance Risk of Context API
217217

218218
The Context API is a fantastic, standard solution in React for avoiding "prop drilling" the tedious process of passing data deep through the component tree. However, when used for complex state management, it carries an often-overlooked architectural risk.
219219

@@ -236,7 +236,7 @@ Therefore, the fundamental principle to follow when using Context API is: Contex
236236

237237
![Context vs Zustand Renders](/Images/Blog/context-vs-zustand-renders.gif)
238238

239-
## Alternative Approaches to Safeguard Performance
239+
### Alternative Approaches to Safeguard Performance
240240

241241
If your application has data that updates frequently and is shared across many components, you can use the following methods to bypass the limitations of the Context API:
242242

@@ -246,15 +246,15 @@ If your application has data that updates frequently and is shared across many c
246246

247247
These architectural choices prevent your application from being rebuilt unnecessarily, allowing React to focus exactly where it was designed to: on the parts that actually change.
248248

249-
# When Should You Use useMemo and useCallback?
249+
## When Should You Use useMemo and useCallback?
250250

251251
In the React ecosystem, `useMemo` and `useCallback` are usually the first tools that come to mind when it comes to boosting performance. However, this popularity often leads to these hooks being used far more than necessary and in the wrong places a pitfall known as **over-optimization**.
252252

253253
It is essential to keep this architectural rule in mind: **Memoization is not free.**
254254

255255
For React to execute these hooks, it must compare each element in the dependency array during every render cycle and store the generated result or reference in memory. When used indiscriminately everywhere, their own execution and memory overhead can actually start to slow down your application instead of providing a performance gain.
256256

257-
### Incorrect (Unnecessary) Usage
257+
#### Incorrect (Unnecessary) Usage
258258

259259
One of the most common mistakes made out of performance anxiety is using `useMemo` for simple primitive operations:
260260

@@ -268,7 +268,7 @@ JavaScript engines solve these types of basic mathematical, string, or boolean o
268268

269269
![React UseMemo Performance ](/Images/Blog/react-usememo-performance.gif)
270270

271-
### Correct Usage Scenarios
271+
#### Correct Usage Scenarios
272272

273273
To truly improve performance, you should only use these hooks in these three specific scenarios:
274274

@@ -278,7 +278,7 @@ To truly improve performance, you should only use these hooks in these three spe
278278

279279
In short, do not attempt to optimize prematurely unless there is a measured performance bottleneck. React is already fast enough in most cases. Memoization used in the wrong places adds an invisible weight to your application rather than speeding it up.
280280

281-
# Real Architectural Principles in Large Scale React Applications
281+
## Real Architectural Principles in Large Scale React Applications
282282

283283
Lasting and sustainable performance gains in React applications aren't achieved by sprinkling `useMemo` or `useCallback` into every corner of the code. True optimization stems from building a solid component architecture. Hooks should not be treated as bandages to cover the flaws of a poorly designed architecture; they are fine-tuning tools for a well-engineered system.
284284

@@ -290,15 +290,15 @@ To safeguard performance in large-scale projects, the following architectural pr
290290
* **Ensuring Referential Stability:** Keep the memory references of objects, arrays, or functions passed as props to expensive child components stable. This prevents `React.memo` from failing its shallow comparison check.
291291
* **Implementing Virtualization:** No matter how optimized your code is, adding thousands of nodes to the DOM will strain the browser. Use tools like `react-window` for long lists or data tables to render only the parts currently visible to the user.
292292

293-
### The Most Critical Question
293+
#### The Most Critical Question
294294

295295
When making architectural decisions or troubleshooting a performance issue, the first and most critical question should always be:
296296

297297
**"Why is this component rendering right now?"**
298298

299299
The answer to this question should be found through measurement tools, not assumptions. Any optimization hook added to the code without identifying the root cause will likely be ineffective and serve only to decrease code readability.
300300

301-
# React DevTools Profiler: Real-World Performance Analysis
301+
## React DevTools Profiler: Real-World Performance Analysis
302302

303303
Relying on intuition or assumptions when solving performance issues often leads to memoizing the wrong components and creating unnecessary code clutter. In the React ecosystem, a true optimization process begins with using the official extension: the **React DevTools Profiler**.
304304

@@ -312,7 +312,7 @@ When you take a recording with the Profiler during an interaction (such as click
312312

313313
Every `useMemo`, `useCallback`, or `React.memo` added to the code without measurement is merely a blind guess. Identifying the root cause of a problem with Profiler data and building a solution based on that evidence is what constitutes true engineering.
314314

315-
# React Performance Is an Architectural Concern, Not Just a Hook Matter
315+
## React Performance Is an Architectural Concern, Not Just a Hook Matter
316316

317317
The foundation of sustainable performance in React applications is not about littering your code with memoization hooks; it is about building a well-structured component architecture from the start. A well-designed component tree, where responsibilities are clearly distributed and data flow is predictable, often eliminates the need for extra optimization tools like `useMemo` or `React.memo`.
318318

0 commit comments

Comments
 (0)