You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: blog-posts/en/react-performance-and-preventing-unnecessary-re-renders.md
+19-19Lines changed: 19 additions & 19 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -11,7 +11,7 @@ Re-rendering in React is not a flaw; it is the framework's fundamental operating
11
11
12
12
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.
13
13
14
-
# What Does "Re-rendering" Actually Mean in React?
14
+
##What Does "Re-rendering" Actually Mean in React?
15
15
16
16
When a component renders in React, the DOM is not directly rebuilt from scratch. Instead, the following sequence of events occurs:
17
17
@@ -29,7 +29,7 @@ While React is highly efficient at minimizing actual DOM manipulations, the re-e
29
29
30
30
Therefore, the primary goal of React performance optimization is not to manage the DOM, but to reduce unnecessary component executions.
31
31
32
-
# Why Do React Components Re-render?
32
+
##Why Do React Components Re-render?
33
33
34
34
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.
35
35
@@ -58,7 +58,7 @@ In this scenario, `HeavyComponent` doesn't use the `count` state at all. However
58
58
59
59

60
60
61
-
# The Most Critical Performance Principle: State Locality
61
+
##The Most Critical Performance Principle: State Locality
62
62
63
63
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).
64
64
@@ -96,7 +96,7 @@ Now, when the button is clicked, the only thing that changes is the internal wor
96
96
97
97
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.
98
98
99
-
# What Does React.memo Actually Do? (A Shield Against Unnecessary Renders)
99
+
##What Does React.memo Actually Do? (A Shield Against Unnecessary Renders)
100
100
101
101
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.
102
102
@@ -127,15 +127,15 @@ Wrapping every single component in `React.memo` is an anti-pattern. The checking
127
127
***Large lists:** Lists containing thousands of rows of data.
128
128
***Heavy UI elements:** Charts, interactive maps, complex data tables, and dashboard components.
129
129
130
-
## A Small Detail (And a Big Danger): Shallow Comparison
130
+
###A Small Detail (And a Big Danger): Shallow Comparison
131
131
132
132
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**.
133
133
134
134
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.
135
135
136
136
This is exactly why **Referential Stability** is of paramount importance for `React.memo` to function as intended.
137
137
138
-
# The Most Common Performance Issue: Referential Instability
138
+
##The Most Common Performance Issue: Referential Instability
139
139
140
140
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).
141
141
@@ -148,7 +148,7 @@ This implies that two completely identical objects are not equal to each other i
148
148
149
149
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.
150
150
151
-
## A Problematic Approach
151
+
###A Problematic Approach
152
152
153
153
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.
154
154
@@ -160,7 +160,7 @@ In the example below, a new object is directly defined for the `config` prop eve
160
160
161
161
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.
162
162
163
-
## Stabilizing References
163
+
###Stabilizing References
164
164
165
165
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:
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`.
190
190
191
-
# The Real Performance Bottleneck: Component Execution Cost
191
+
##The Real Performance Bottleneck: Component Execution Cost
192
192
193
193
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.
194
194
@@ -205,15 +205,15 @@ Real performance costs typically stem from the following:
205
205
206
206
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.
207
207
208
-
## The Solution: Virtualization
208
+
###The Solution: Virtualization
209
209
210
210
When rendering massive data lists, `React.memo` alone isn't enough. In these cases, the essential architectural approach is **Virtualization**.
211
211
212
212
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**.
213
213
214
214
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.
215
215
216
-
# The Hidden Performance Risk of Context API
216
+
##The Hidden Performance Risk of Context API
217
217
218
218
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.
219
219
@@ -236,7 +236,7 @@ Therefore, the fundamental principle to follow when using Context API is: Contex
236
236
237
237

238
238
239
-
## Alternative Approaches to Safeguard Performance
239
+
###Alternative Approaches to Safeguard Performance
240
240
241
241
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:
242
242
@@ -246,15 +246,15 @@ If your application has data that updates frequently and is shared across many c
246
246
247
247
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.
248
248
249
-
# When Should You Use useMemo and useCallback?
249
+
##When Should You Use useMemo and useCallback?
250
250
251
251
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**.
252
252
253
253
It is essential to keep this architectural rule in mind: **Memoization is not free.**
254
254
255
255
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.
256
256
257
-
### Incorrect (Unnecessary) Usage
257
+
####Incorrect (Unnecessary) Usage
258
258
259
259
One of the most common mistakes made out of performance anxiety is using `useMemo` for simple primitive operations:
260
260
@@ -268,7 +268,7 @@ JavaScript engines solve these types of basic mathematical, string, or boolean o
To truly improve performance, you should only use these hooks in these three specific scenarios:
274
274
@@ -278,7 +278,7 @@ To truly improve performance, you should only use these hooks in these three spe
278
278
279
279
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.
280
280
281
-
# Real Architectural Principles in Large Scale React Applications
281
+
##Real Architectural Principles in Large Scale React Applications
282
282
283
283
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.
284
284
@@ -290,15 +290,15 @@ To safeguard performance in large-scale projects, the following architectural pr
290
290
***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.
291
291
***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.
292
292
293
-
### The Most Critical Question
293
+
####The Most Critical Question
294
294
295
295
When making architectural decisions or troubleshooting a performance issue, the first and most critical question should always be:
296
296
297
297
**"Why is this component rendering right now?"**
298
298
299
299
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.
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**.
304
304
@@ -312,7 +312,7 @@ When you take a recording with the Profiler during an interaction (such as click
312
312
313
313
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.
314
314
315
-
# React Performance Is an Architectural Concern, Not Just a Hook Matter
315
+
##React Performance Is an Architectural Concern, Not Just a Hook Matter
316
316
317
317
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`.
0 commit comments