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
{{ message }}
/ ... /
coryhouse / reactjsconsulting / Issues #77 /
Clear Command Palette
Tip:
Type # to search pull requests
Type ? for help and tips
Tip:
Type # to search issues
Type ? for help and tips
Tip:
Type # to search discussions
Type ? for help and tips
Tip:
Type ! to search projects
Type ? for help and tips
Tip:
Type @ to search teams
Type ? for help and tips
Tip:
Type @ to search people and organizations
Type ? for help and tips
Tip:
Type > to activate command mode
Type ? for help and tips
Tip:
Go to your accessibility settings to change your keyboard shortcuts
Type ? for help and tips
Tip:
Type author:@me to search your content
Type ? for help and tips
Tip:
Type is:pr to filter to pull requests
Type ? for help and tips
Tip:
Type is:issue to filter to issues
Type ? for help and tips
Tip:
Type is:project to filter to projects
Type ? for help and tips
Tip:
Type is:open to filter to open content
Type ? for help and tips
We’ve encountered an error and some results aren't available at this time. Type a new search or try again later.
No results matched your search
Top result
Commands
Type > to filter
Global Commands
Type > to filter
This Page
Files
Pages
Access Policies
Organizations
Repositories
Issues, pull requests, and discussions
Type # to filter
Teams
Users
Projects
Projects (classic)
Modes
Use filters in issues, pull requests, discussions, and projects
Search for issues and pull requests#Search for issues, pull requests, discussions, and projects#Search for organizations, repositories, and users@Search for projects!Search for files/Activate command mode>Search your issues, pull requests, and discussions# author:@meSearch your issues, pull requests, and discussions# author:@meFilter to pull requests# is:prFilter to issues# is:issueFilter to discussions# is:discussionFilter to projects# is:projectFilter to open issues, pull requests, and discussions# is:open
Analyze performance via the React dev tools.
通过 React 开发工具分析性能。
Use React dev tools "Highlight Updates" to see what's re-rendering. Then be strategic.
使用 React 开发工具 "突出显示更新 "来查看重新渲染的内容。然后采取策略。
Ask: why is this component re-rendering? 问:为什么这个组件要重新渲染?
Ask: Could I avoid passing the prop that's causing it to re-render? Could it access this data via Context instead to avoid passing it through intermediate components that don't need it? 问:我能否避免传递导致重新渲染的道具?是否可以通过 "上下文 "访问这些数据,以避免通过不需要这些数据的中间组件?
Use console.time like this, against the prod build, to measure slowness and compare to a before and after to determine if useMemo is a net win: console.time('filter array'); const visibleTodos = getFilteredTodos(todos, filter); console.timeEnd('filter array'); 像这样使用 console.time ,与原型构建对比,测量速度慢的程度,并与之前和之后进行比较,以确定 useMemo 是否净赢: console.time('filter array'); const visibleTodos = getFilteredTodos(todos, filter); console.timeEnd('filter array');
functionExpensiveTree(){letnow=performance.now();while(performance.now()-now<100){// Artificial delay -- do nothing for 100ms}return<p>I am a very slow component tree.</p>;}
Consider uncontrolled components for large, expensive forms. In other words, Handle state in each input. Here is my approach which was loosely inspired by Kent's Fast forms blog post - he provides an (unfortunately contrived, incomplete, and buggy) example, but the core idea is sound. For uncontrolled forms, also consider via react-hookform 对于大型、昂贵的表格,应考虑使用不受控制的组件。换句话说,在每个输入中处理状态。以下是我的方法,灵感来源于 Kent 的快速表单博文--他提供了一个例子(不幸的是,这个例子是臆造的、不完整的、有漏洞的),但核心思想是正确的。对于不受控制的表单,也可以考虑使用 react-hookform
Statically render if possible (Easy via Next.js, Gatsby) 尽可能进行静态渲染(通过 Next.js、Gatsby 可轻松实现)
Consider server rendering to avoid slow network waterfalls (easy via Remix / Next.js) 考虑服务器渲染,避免缓慢的网络瀑布(通过 Remix / Next.js 轻松实现)
Prefetch / render-as-you-fetch (React's "default" is fetch as you render since the render triggers a fetch via useEffect). React-query's prefetching is a simple way to render as you fetch. Remix also does this by default since nested routes declare data dependencies and run in parallel on the server. My tweet on this 预取/边渲染边获取(React 的 "默认 "是边渲染边获取,因为渲染会通过 useEffect 触发获取)。React-query 的预取是一种边渲染边获取的简单方法。Remix 默认也是如此,因为嵌套路由会声明数据依赖关系,并在服务器上并行运行。我的推文
If server rendering with Remix, Next, Docusaurus, etc, Enable time-slicing with React.startTransition at the root. This avoids jank if the user scrolls before hydration completes. 如果使用 Remix、Next、Docusaurus 等进行服务器渲染,请在根目录下使用 React.startTransition 启用时间分割。这样可以避免在水合完成前用户滚动时出现抖动。
Consider using million's block virtual DOM instead if there is a lot of static content with little dynamic content. Million diffs state instead of DOM, which is fast if there's a little state, but a LOT of DOM. 如果静态内容较多,而动态内容较少,可以考虑使用 million 的块虚拟 DOM。如果只有少量的状态,而 DOM 却很多,那么使用百万的块虚拟 DOM 会更快。
Context 背景
Minimize context usage - Consider component composition instead (composing components that accept children, so props "Lifted" / composed at a higher level in the tree). Dan calls this lift content up. 尽量减少上下文的使用--考虑组件组合(组合接受子组件的组件,因此道具 "提升"/组合在树的更高层次)。丹将此称为 "提升内容"。
Avoid putting data that changes a lot in context 避免将变化较大的数据置于上下文中
Separate contexts based on when they change 根据上下文变化的时间将其分开
Place context providers as low as possible 尽可能降低背景提供者的位置
Wrap the component directly under your context provider in React.memo or use {props.children} - This means changes to the context value will rerender only the components consuming the context instead of the entire subtree. More here. Here's a codesandbox showing how to memo children. And here's a visual example of using memo on the direct child. 在 React.memo 中直接将组件包裹在上下文提供者之下,或使用 {props.children} - 这意味着上下文值的更改只会重新渲染使用上下文的组件,而不是整个子树。点击此处了解更多。下面的代码框展示了如何备忘录子代。下面是在直接子代上使用 memo 的可视化示例。
Routing 路由
Implement client-side routing via React Router (or you frameworks built-in alternative, such as Next.js) 通过 React Router(或框架内置的替代方案,如 Next.js)实施客户端路由。
Keys 钥匙
Assure keys are assigned, and stable over time. Their values should not change based on array order or edits to the data. 确保键已分配,并随时间推移保持稳定。它们的值不应根据数组顺序或对数据的编辑而改变。
Reuse keys to avoid needless renders for items that frequently appear/disappear in the viewport. 对于在视口中频繁出现/消失的项目,重复使用按键可避免不必要的渲染。
Consider using the array’s index as key for dynamic lists with stateless items, where items are replaced with the new ones - paginated lists, search and autocomplete results and the like. This will improve the list’s performance because the entire thing doesn't have to re-render. The component instances are reused. Demo and blog post 考虑将数组的索引作为 key 用于具有无状态项的动态列表,在这种列表中,项会被新的项替换--分页列表、搜索和自动完成结果等。这将提高列表的性能,因为整个列表无需重新渲染。组件实例可以重复使用。演示和博文
State 国家
Keep state as local as possible. Start by declaring state in the component that uses it. Lift as needed. 尽可能保持状态的本地化。首先在使用状态的组件中声明状态。根据需要进行提升。
Store data that doesn't need to render in refs 将不需要渲染的数据存储在引用中
Consider useReducer over useState so you can pass dispatch down instead of callbacks (avoids needless renders) 考虑使用 reduceer 而不是 useState,这样就可以向下传递调度而不是回调(避免不必要的渲染)。
Avoid deep cloning. To avoid, only clone the subobjects that have changed. Or perhaps better yet, avoid nesting objects in state since doing so can lead to needless renders. Instead, "flatten" state by creating separate pieces of state. 避免深度克隆。要避免深度克隆,只克隆发生变化的子对象。或许更好的做法是,避免在状态中嵌套对象,因为这样做会导致不必要的渲染。相反,通过创建独立的状态块来 "扁平化 "状态。
Use useTransition for low priority updates (reduces jank) - Demo 对低优先级更新使用 useTransition (减少垃圾信息) - 演示
Use useLayoutEffect to avoid a Flash of unstyled content when you need to read and manipulate the DOM before the user sees it - Demo 当您需要在用户看到内容之前读取并操作 DOM 时,使用 useLayoutEffect 可避免出现未样式化的 Flash 内容 - 演示
Memoization / Identity 记忆化/身份
Memoize expensive operations via useMemo 通过 useMemo 将昂贵的操作记忆化
Avoid needless renders via React.memo 通过 React.memo 避免不必要的渲染
Consider wrapping functions passed to children in useCallback to avoid needless renders in children 考虑在 useCallback 中封装传递给子代的函数,以避免子代中不必要的渲染
Prefer pure functions (which can be extracted from the component) over useCallback when possible 尽可能选择纯函数(可从组件中提取),而不是 useCallback
Props 道具
Pass the minimal amount of data to each component (remember, components re-render when props change) 向每个组件传递最少的数据量(记住,当道具发生变化时,组件会重新渲染)
Pass primitives (strings, numbers...) to child components to assist with diffing. Avoid passing arrow funcs and objects on props when performance is a concern since it leads to needless re-renders of child components. 将基元(字符串、数字......)传递给子组件,以协助差异化。如果对性能有要求,应避免在道具上传递箭头函数和对象,因为这会导致子组件不必要的重新渲染。
useDeferredValue if it's a low priority update and you can't use useTransition because you don't control the value coming in (coming from third party or via a prop you can't control). Another demo 如果是低优先级更新,并且由于无法控制输入值(来自第三方或通过无法控制的道具)而不能使用 useTransition ,则使用 useDeferredValue。另一个演示
Component composition / Children 组件构成/儿童
Put content that renders frequently in a separate component to minimize the amount that's rendered 将频繁渲染的内容放在单独的组件中,以尽量减少渲染量
Embrace reusable components. Each reuse of a reusable component is nearly free. 拥抱可重复使用的组件。可重复使用组件的每次重复使用几乎都是免费的。
Compose higher level components out of lower level components. 由低级组件组成高级组件。
Create layout components to centralize reusable layout 创建布局组件,集中管理可重复使用的布局
Declare functions that need not be in the React component outside the component. This way they're not reallocated on every render. 在 React 组件外部声明不需要的函数。这样,它们就不会在每次呈现时重新分配。
Declare static values outside the component so they're not reallocated on every render. 在组件外部声明静态值,这样它们就不会在每次呈现时重新分配。
Design 设计
Use pagination, sorting, filtering, pages, tabs, accordions, modals, etc to avoid displaying too much data at the same time. 使用分页、排序、过滤、页面、标签、手风琴、模态等方式,避免同时显示过多数据。
Use tools like react-window to handle large lists by only rendering what's currently visible. 使用 react-window 等工具处理大型列表,只呈现当前可见的内容。
Consider implementing optimistic updates when the API is slow (immediately update the UI even though the API call is still in progress behind the scenes) 当应用程序接口运行缓慢时,考虑实施乐观更新(即使应用程序接口调用仍在幕后进行,也要立即更新用户界面)
Bundle optimization 捆绑优化
Split the bundle via React.lazy or use loadable-components. Not merely pages. Consider splitting components too. Remember that Next.js automatically bundle splits. 通过 React.lazy 或使用可加载组件拆分捆绑包。不仅仅是页面。也可以考虑拆分组件。请记住,Next.js 会自动进行捆绑拆分。
Check what's in your bundle via webpack-bundle-analyzer 通过 webpack-bundle-analyzer 查看捆绑包中的内容
Third party libraries 第三方图书馆
Avoid named imports when importing third party libraries / components (doing so can bloat the bundle by importing the entire lib) For example, avoid import { Tab } from "x". Prefer import Tab from "x/Tab" when possible. 在导入第三方库/组件时避免命名导入(这样做可能会导入整个库,从而使捆绑包变得臃肿),例如,避免使用 import { Tab } from "x" .尽可能选择 import Tab from "x/Tab" 。
Prefer native HTML inputs over fancy components that simulate native behaviors 优先选择本地 HTML 输入,而不是模拟本地行为的花哨组件
Use Partytown to load heavy third party libraries via a separate web worker thread 使用 Partytown,通过单独的网络工作线程加载繁重的第三方库
Styling 造型设计
Consider Tailwind to minimize style bundle size 考虑使用 Tailwind 尽量减少样式捆绑包的大小
Consider CSS modules over CSS-in-JS to avoid a runtime 考虑 CSS 模块而非 CSS-in-JS 以避免运行时
Framework 框架
Consider Gatsby or Astrobuild to compile components into static HTML 考虑使用 Gatsby 或 Astrobuild 将组件编译成静态 HTML
Consider Next.js, Remix, Redwood to server render 考虑将 Next.js、Remix 和 Redwood 用于服务器渲染
Sorry, something went wrong.
42+ ways to make your React app faster ⚛️:
让 React 应用程序更快的 42+ 种方法 ⚛️:
Performance Testing 性能测试
检查核心网络生命体征,如 INP
使用 https://million.dev/lint
通过 React 开发工具分析性能。
使用 React 开发工具 "突出显示更新 "来查看重新渲染的内容。然后采取策略。
问:为什么这个组件要重新渲染?
问:我能否避免传递导致重新渲染的道具?是否可以通过 "上下文 "访问这些数据,以避免通过不需要这些数据的中间组件?
启用每个组件渲染的原因。
学习使用 React 剖析器,并阅读火焰图:黄色 = 花费更多时间。蓝色 = 耗时较少。灰色 = 本次提交期间未渲染。( 源代码)
console.time
like this, against the prod build, to measure slowness and compare to a before and after to determine ifuseMemo
is a net win:console.time('filter array'); const visibleTodos = getFilteredTodos(todos, filter); console.timeEnd('filter array');
像这样使用
console.time
,与原型构建对比,测量速度慢的程度,并与之前和之后进行比较,以确定useMemo
是否净赢:console.time('filter array'); const visibleTodos = getFilteredTodos(todos, filter); console.timeEnd('filter array');
使用 https://github.com/welldone-software/why-did-you-render
使用 Chrome 浏览器的 CPU 和网络减速功能
小贴士以 JSON 格式存储大型模拟数据集/配置对象。解析速度会快 80%。
使用以下选项之一创建/模拟大型数据集/慢速组件
Generate a simple fake dataset in a loop.
循环生成一个简单的假数据集。
Generate a large fake dataset using tools like Faker, Chance, etc.
使用 Faker、Chance 等工具生成一个大型假数据集。
Simulate a slow component via a loop:
通过循环模拟慢速分量
Forms 表格
将长表格分割成不同步骤
对于大型、昂贵的表格,应考虑使用不受控制的组件。换句话说,在每个输入中处理状态。以下是我的方法,灵感来源于 Kent 的快速表单博文--他提供了一个例子(不幸的是,这个例子是臆造的、不完整的、有漏洞的),但核心思想是正确的。对于不受控制的表单,也可以考虑使用 react-hookform
HTTP 超文本传输协定
通过 react-query/swr/Apollo 等缓存 HTTP 请求。
提升状态,避免重复呼叫
使用 Promise.all 并行调用
使用 useOnScreen 等工具,在折叠下方懒加载内容
简化 HTTP 请求--只获取必要的数据
使用 setQueryData 预填充详情页缓存。现在,详细页面会立即加载。
Rendering 效果图
尽可能进行静态渲染(通过 Next.js、Gatsby 可轻松实现)
考虑服务器渲染,避免缓慢的网络瀑布(通过 Remix / Next.js 轻松实现)
useEffect
). React-query's prefetching is a simple way to render as you fetch. Remix also does this by default since nested routes declare data dependencies and run in parallel on the server. My tweet on this预取/边渲染边获取(React 的 "默认 "是边渲染边获取,因为渲染会通过
useEffect
触发获取)。React-query 的预取是一种边渲染边获取的简单方法。Remix 默认也是如此,因为嵌套路由会声明数据依赖关系,并在服务器上并行运行。我的推文如果使用 Remix、Next、Docusaurus 等进行服务器渲染,请在根目录下使用 React.startTransition 启用时间分割。这样可以避免在水合完成前用户滚动时出现抖动。
如果静态内容较多,而动态内容较少,可以考虑使用 million 的块虚拟 DOM。如果只有少量的状态,而 DOM 却很多,那么使用百万的块虚拟 DOM 会更快。
Context 背景
尽量减少上下文的使用--考虑组件组合(组合接受子组件的组件,因此道具 "提升"/组合在树的更高层次)。丹将此称为 "提升内容"。
避免将变化较大的数据置于上下文中
根据上下文变化的时间将其分开
尽可能降低背景提供者的位置
考虑将状态和调度分离到不同的上下文中
在 React.memo 中直接将组件包裹在上下文提供者之下,或使用 {props.children} - 这意味着上下文值的更改只会重新渲染使用上下文的组件,而不是整个子树。点击此处了解更多。下面的代码框展示了如何备忘录子代。下面是在直接子代上使用 memo 的可视化示例。
Routing 路由
通过 React Router(或框架内置的替代方案,如 Next.js)实施客户端路由。
Keys 钥匙
确保键已分配,并随时间推移保持稳定。它们的值不应根据数组顺序或对数据的编辑而改变。
对于在视口中频繁出现/消失的项目,重复使用按键可避免不必要的渲染。
key
for dynamic lists with stateless items, where items are replaced with the new ones - paginated lists, search and autocomplete results and the like. This will improve the list’s performance because the entire thing doesn't have to re-render. The component instances are reused. Demo and blog post考虑将数组的索引作为
key
用于具有无状态项的动态列表,在这种列表中,项会被新的项替换--分页列表、搜索和自动完成结果等。这将提高列表的性能,因为整个列表无需重新渲染。组件实例可以重复使用。演示和博文State 国家
尽可能保持状态的本地化。首先在使用状态的组件中声明状态。根据需要进行提升。
将不需要渲染的数据存储在引用中
考虑使用 reduceer 而不是 useState,这样就可以向下传递调度而不是回调(避免不必要的渲染)。
避免深度克隆。要避免深度克隆,只克隆发生变化的子对象。或许更好的做法是,避免在状态中嵌套对象,因为这样做会导致不必要的渲染。相反,通过创建独立的状态块来 "扁平化 "状态。
如果初始值调用了昂贵的函数,则使用 memo、ref 或向 useState 传递一个函数;否则,将在每次呈现时计算初始值。
useTransition
for low priority updates (reduces jank) - Demo对低优先级更新使用
useTransition
(减少垃圾信息) - 演示useLayoutEffect
to avoid a Flash of unstyled content when you need to read and manipulate the DOM before the user sees it - Demo当您需要在用户看到内容之前读取并操作 DOM 时,使用
useLayoutEffect
可避免出现未样式化的 Flash 内容 - 演示Memoization / Identity 记忆化/身份
通过 useMemo 将昂贵的操作记忆化
通过 React.memo 避免不必要的渲染
考虑在 useCallback 中封装传递给子代的函数,以避免子代中不必要的渲染
尽可能选择纯函数(可从组件中提取),而不是 useCallback
Props 道具
向每个组件传递最少的数据量(记住,当道具发生变化时,组件会重新渲染)
将基元(字符串、数字......)传递给子组件,以协助差异化。如果对性能有要求,应避免在道具上传递箭头函数和对象,因为这会导致子组件不必要的重新渲染。
useTransition
because you don't control the value coming in (coming from third party or via a prop you can't control). Another demo如果是低优先级更新,并且由于无法控制输入值(来自第三方或通过无法控制的道具)而不能使用
useTransition
,则使用 useDeferredValue。另一个演示Component composition / Children
组件构成/儿童
将频繁渲染的内容放在单独的组件中,以尽量减少渲染量
拥抱可重复使用的组件。可重复使用组件的每次重复使用几乎都是免费的。
由低级组件组成高级组件。
创建布局组件,集中管理可重复使用的布局
children
don’t re-render since they are just props. Note: don't pass a function as a child, since it'll still re-render because the func will be recreated on each render将内容向上提升 - 将孩子向下传递(在备忘录之前这样做)。为什么这样做可行?因为作为
children
传递的组件不会重新渲染,因为它们只是道具。注意:不要将函数作为子代传递,因为它仍会重新渲染,因为每次渲染时都会重新创建函数在 React 组件外部声明不需要的函数。这样,它们就不会在每次呈现时重新分配。
在组件外部声明静态值,这样它们就不会在每次呈现时重新分配。
Design 设计
使用分页、排序、过滤、页面、标签、手风琴、模态等方式,避免同时显示过多数据。
使用 react-window 等工具处理大型列表,只呈现当前可见的内容。
当应用程序接口运行缓慢时,考虑实施乐观更新(即使应用程序接口调用仍在幕后进行,也要立即更新用户界面)
Bundle optimization 捆绑优化
通过 React.lazy 或使用可加载组件拆分捆绑包。不仅仅是页面。也可以考虑拆分组件。请记住,Next.js 会自动进行捆绑拆分。
考虑预取极有可能使用的懒加载组件
在链接悬停时紧急加载懒人路由
通过自定义钩子和纯实用功能实现可重用逻辑
避免使用 lodash、underscore 和 Ramda 等大型实用库。您可能只需要普通的 JS。避免使用这些您可能不需要的库 使用 ESLint 禁止大量/多余的导入
其他可能不应该出现在捆绑包中的内容 - 通过 ESlint 以编程方式强制执行。
以 JSON 格式存储大型配置对象。解析速度快 80%。
通过 webpack-bundle-analyzer 查看捆绑包中的内容
Third party libraries 第三方图书馆
import { Tab } from "x"
. Preferimport Tab from "x/Tab"
when possible.在导入第三方库/组件时避免命名导入(这样做可能会导入整个库,从而使捆绑包变得臃肿),例如,避免使用
import { Tab } from "x"
.尽可能选择import Tab from "x/Tab"
。优先选择本地 HTML 输入,而不是模拟本地行为的花哨组件
使用 Partytown,通过单独的网络工作线程加载繁重的第三方库
Styling 造型设计
考虑使用 Tailwind 尽量减少样式捆绑包的大小
考虑 CSS 模块而非 CSS-in-JS 以避免运行时
Framework 框架
考虑使用 Gatsby 或 Astrobuild 将组件编译成静态 HTML
考虑将 Next.js、Remix 和 Redwood 用于服务器渲染
More examples 更多实例
https://piyushsinha.tech/optimizing-performance-in-react-apps-i
https://piyushsinha.tech/optimizing-performance-in-react-apps-ii
The text was updated successfully, but these errors were encountered: