惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

量子位
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园_首页
AWS News Blog
AWS News Blog
阮一峰的网络日志
阮一峰的网络日志
Vercel News
Vercel News
C
Cybersecurity and Infrastructure Security Agency CISA
P
Proofpoint News Feed
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
Tailwind CSS Blog
PCI Perspectives
PCI Perspectives
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - 叶小钗
IT之家
IT之家
V2EX - 技术
V2EX - 技术
Cloudbric
Cloudbric
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
宝玉的分享
宝玉的分享
Know Your Adversary
Know Your Adversary
爱范儿
爱范儿
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Schneier on Security
博客园 - 【当耐特】
G
Google Developers Blog
S
Security @ Cisco Blogs
N
Netflix TechBlog - Medium
T
Tenable Blog
C
Check Point Blog
The Cloudflare Blog
J
Java Code Geeks
The Register - Security
The Register - Security
Google Online Security Blog
Google Online Security Blog
Security Latest
Security Latest
T
Tor Project blog
T
The Blog of Author Tim Ferriss
S
Security Affairs
S
Securelist
P
Privacy & Cybersecurity Law Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
P
Privacy International News Feed
博客园 - 三生石上(FineUI控件)
D
DataBreaches.Net
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
A
About on SuperTechFans
G
GRAHAM CLULEY
Jina AI
Jina AI
Spread Privacy
Spread Privacy

Kent C. Dodds Blog

Implementing Hybrid Semantic + Lexical Search Simplifying Containers with Cloudflare Sandboxes Migrating to Workspaces and Nx Offloading FFmpeg with Cloudflare Building Semantic Search on my Content Helping YOU ask ME questions with AI How I used Cursor to Migrate Frameworks The Dow's Start on the Covenant Path 2025 in Review The next chapter: EpicAI.pro AI is taking your job How I increased my visibility Launching Epic Web 2023 in Review Stop Being a Junior RSC with Dan Abramov and Joe Savona Live Stream Fixing a Memory Leak in a Production Node.js App 2022 in Review My Car Accident I Migrated from a Postgres Cluster to Distributed SQLite with LiteFS I'm building EpicWeb.dev A review of my time at Remix Remix: The Yang to React's Yin How I help you build better websites Why I Love Remix The State Initializer Pattern How to React ⚛️ Get a catch block error message with TypeScript Building an awesome image loading experience How Remix makes CSS clashes predictable Introducing the new kentcdodds.com How I built a modern website in 2021 How to use React Context effectively Static vs Unit vs Integration vs E2E Testing for Frontend Apps The Testing Trophy and Testing Classifications Array reduce vs chaining vs for loop Don't Solve Problems, Eliminate Them Super Simple Start to Remix Super Simple Start to ESModules in Node.js JavaScript Pass By Value Function Parameters How to write a Constrained Identity Function (CIF) in TypeScript How to optimize your context value How to write a React Component in TypeScript TypeScript Function Syntaxes Listify a JavaScript Array Build vs Buy: Component Libraries edition Using fetch with TypeScript Wrapping React.useState with TypeScript Define function overload types with TypeScript 2020 in Review Business and Engineering alignment Hi, thanks for reaching out to me 👋 useEffect vs useLayoutEffect Super simple start to Firebase functions Super simple start to Netlify functions Super Simple Start to css variables Favor Progress Over Pride in Open Source Testing Implementation Details How getting into Open Source has been awesome for me useState lazy initialization and function updates Use ternaries rather than && in JSX Application State Management with React Use react-error-boundary to handle errors in React JavaScript to Know for React How I structure Express apps What open source project should I contribute to? When I follow TDD AHA Programming 💡 How I Record Educational Videos Should I write a test or fix a bug? Stop mocking fetch Intentional Career Building Improve test error messages of your abstractions Tracing user interactions with React Eliminate an entire category of bugs with a few simple tools Common mistakes with React Testing Library Super Simple Start to React Stop using client-side route redirects The State Reducer Pattern with React Hooks Function forms Replace axios with a simple custom fetch wrapper How to test custom React hooks React Production Performance Monitoring Should I useState or useReducer? Stop using isLoading booleans Make Your Test Fail Make your own DevTools An Argument for Automation Fix the "not wrapped in act(...)" warning Super Simple Start to ESModules in the Browser Implementing a simple state machine library in JavaScript 2010s Decade in Review Why users care about how you write code Why I avoid nesting closures Don't call a React function component Why your team needs TestingJavaScript.com Inversion of Control Understanding React's key prop How to Enable React Concurrent Mode Profile a React App for Performance
Fix the slow render before you fix the re-render
Kent C. Dodds 🏹 @kentcdodds · 2019-09-09 · via Kent C. Dodds Blog

Performance is a serious issue and we should make our apps as fast as possible. How we go about doing that will make a big impact on not only the effectiveness of our optimizations but also the complexity of our code (how quickly we can make improvements and changes in the future).

When we're talking about React optimizations, one of the things that people bring up a lot is optimizing "re-renders." Let's make sure we're talking about the same thing:

function Counter() {
	const [count, setCount] = React.useState(0)
	const increment = () => setCount((c) => c + 1)
	return <button onClick={increment}>{count}</button>
}

Every time we click on that button, we're triggering a re-render. But what is a "re-render"?

What is a re-render?

When React was first released, a lot of people focused on the performance improvements over existing UI libraries thanks to React's "Virtual DOM". Most popular existing UI libraries at the time would either leave you to update the DOM yourself, or would update the DOM for you, but do so sequentially for every "component" (or directive) that needed updating. Basically it comes down to this:

  1. Given that it's slow to update the DOM (like when calling element.appendChild(childElement) for example).
  2. And that performance issue is compounded the more times you do it.
  3. And can side-step some perf issues by doing all necessary updates at once
  4. If we batch all DOM updates, then we can reduce the performance issues of updating the DOM multiple times in rapid succession.

So the React team decided to batch DOM updates, so if there was a state change that resulted in thirty DOM updates, they would all happen at once, rather than running them one after another. To do this batching though, they would have to take ownership over updating the DOM, so we have React.createElement (which is what JSX is) to describe what we want the DOM to look like, and when there's a state change, React calls our function again to get the React elements we need rendered to the DOM. It then compares those new React elements with the ones we gave it last time we rendered. From that it can tell what DOM updates to make, and then makes those updates for us in the most performant way possible. The process of updating the DOM is called "committing" because we're taking the React elements that you "rendered" and "commit" those updates to the DOM.

This is a really important distinction and I don't want you to miss it (and the names are a tiny bit misleading, so I want to make it clear). A "render" is when React calls your function to get React elements. "Reconciliation" is when React compares those React elements with the previously rendered elements. A "commit" is when React takes those differences and makes the DOM updates.

render → reconciliation → commit
      ↖                   ↙
           state change

To be clear:

  • The "render" phase: create React elements React.createElement (learn more)
  • The "reconciliation" phase: compare previous elements with the new ones (learn more)
  • The "commit" phase: update the DOM (if needed).

Typically, the slowest part of this is the "commit" phase when the DOM is updated. But not all DOM updates are slow. In fact, it's probably a bit misleading to state simply that "the DOM is slow" because it's more nuanced than that. DOM updates like adding/removing event listeners are really fast. The slow part of the DOM is "layout" (learn more about slow layout here).

Thanks to React's batching and optimized code, we can avoid a lot of the pitfalls without having to worry ourselves about this problem, but it can definitely bite us on occasion.

Unnecessary re-renders

Just because a component is re-rendered, doesn't mean that will result in a DOM update. Here's a quick contrived example of that:

function Foo() {
	return <div>FOO!</div>
}

function Counter() {
	const [count, setCount] = React.useState(0)
	const increment = () => setCount((c) => c + 1)
	return (
		<>
			<Foo />
			<button onClick={increment}>{count}</button>
		</>
	)
}

Every time you click on the button, the Foo function is called, but the DOM that it represents is not re-rendered. Because of that, there's no DOM update for that component at all. This is commonly referred to as an "unnecessary re-render."

Unfortunately, there's been a fair amount of confusion around the difference between "renders" and "commits." Many people know (or at least they've heard) that "the DOM is slow," but plenty don't realize that just because a component is re-rendered, doesn't mean the DOM will be updated. Because of this misunderstanding, they believe it is a performance bottleneck that a component renders when it doesn't actually need to update the DOM.

This can definitely be a problem in some cases, but in general even mobile browsers on low-end devices are very fast at creating objects (render phase) and comparing them (reconciliation phase). So what's the problem with re-renders?

Slow renders

Given that JavaScript is really fast at handling the render and reconciliation phases, then why is my app freezing up when I'm getting unnecessary re-renders? In that situation, I'd suggest that your problem might be unnecessary re-renders, but it's more likely a problem with slow renders in general. There's something that your code is doing during the render phase that's making things slow. You should diagnose and fix that first. Once you've fixed that problem, then you can profile your app again and see if you still have issues with unnecessary re-renders.

In fact, if you leave in a slow render and just reduce re-renders instead, then you could wind up with a worse situation, and you'll likely wind up with more complicated code.

Maybe this will drive my point home. Let's say that you have to punch yourself in the face every time you blink 😉🤛 🥴. Maybe you'd think: "oh gee, I guess I'd better not blink as much!" You know what I say? I say you should stop punching yourself in the face every time you blink! So instead of just reducing how often a bad thing happens (slow renders), maybe you could eliminate the bad thing and feel free to blink (render) as much as your eyes need you to 😉

stop hitting yourself

How to fix slow renders

So we've concluded we want to fix slow renders first. Then we can determine whether re-renders are still a problem. So how do we fix the slow render. Often you already know which interaction is causing a "janky" experience for the user. Often it's when you open a tab, click a button, or type in a text field.

Here's what you do: Using your browser's profiling tools, start profiling your app, do the interaction, then stop profiling it again. For example:

Once you figure out what part of you (or your dependencies) is taking the longest and fix those problems, then try again with the profiler and observe the improvements (or regressions). Don't miss the React DevTools profiler as well, it's really great!

Conclusion

It doesn't matter if 100% of your renders are necessary, if those renders are slow, it will still produce a bad experience for the user. Stop punching yourself in the face every time you blink. Fix your slow renders first. Then deal with the "unnecessary re-renders" (if you still need to). Good luck!