diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index f250545422..45a6461104 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -4,7 +4,7 @@ title: useDeferredValue -`useDeferredValue` is a React Hook that lets you defer updating a part of the UI. +`useDeferredValue` 是一个 React Hook,可以让你延迟更新 UI 的某些部分。 ```js const deferredValue = useDeferredValue(value) @@ -16,11 +16,11 @@ const deferredValue = useDeferredValue(value) --- -## Reference {/*reference*/} +## 参考 {/*reference*/} ### `useDeferredValue(value)` {/*usedeferredvalue*/} -Call `useDeferredValue` at the top level of your component to get a deferred version of that value. +在组件的顶层调用 `useDeferredValue` 来获取该值的延迟版本。 ```js import { useState, useDeferredValue } from 'react'; @@ -32,37 +32,37 @@ function SearchPage() { } ``` -[See more examples below.](#usage) +[请看下方更多示例](#usage)。 -#### Parameters {/*parameters*/} +#### 参数 {/*parameters*/} -* `value`: The value you want to defer. It can have any type. +* `value`:你想延迟的值,可以是任何类型。 -#### Returns {/*returns*/} +#### 返回值 {/*returns*/} -During the initial render, the returned deferred value will be the same as the value you provided. During updates, React will first attempt a re-render with the old value (so it will return the old value), and then try another re-render in background with the new value (so it will return the updated value). +在组件的初始渲染期间,返回的延迟值将与你提供的值相同。但是在组件更新时,React 将会先尝试使用旧值进行重新渲染(因此它将返回旧值),然后再在后台使用新值进行另一个重新渲染(这时它将返回更新后的值)。 -#### Caveats {/*caveats*/} +#### 注意事项 {/*caveats*/} -- The values you pass to `useDeferredValue` should either be primitive values (like strings and numbers) or objects created outside of rendering. If you create a new object during rendering and immediately pass it to `useDeferredValue`, it will be different on every render, causing unnecessary background re-renders. +- 你应该向 `useDeferredValue` 传递原始值(如字符串和数字)或在渲染之外创建的对象。如果你在渲染期间创建了一个新对象,并立即将其传递给 `useDeferredValue`,那么每次渲染时这个对象都会不同,这将导致后台不必要的重新渲染。 -- When `useDeferredValue` receives a different value (compared with [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), in addition to the current render (when it still uses the previous value), it schedules a re-render in the background with the new value. The background re-render is interruptible: if there's another update to the `value`, React will restart the background re-render from scratch. For example, if the user is typing into an input faster than a chart receiving its deferred value can re-render, the chart will only re-render after the user stops typing. +- 当 `useDeferredValue` 接收到与之前不同的值(使用 [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) 进行比较)时,除了当前渲染(此时它仍然使用旧值),它还会安排一个后台重新渲染。这个后台重新渲染是可以被中断的,如果 `value` 有新的更新,React 会从头开始重新启动后台渲染。举个例子,如果用户在输入框中的输入速度比接收延迟值的图表重新渲染的速度快,那么图表只会在用户停止输入后重新渲染。 -- `useDeferredValue` is integrated with [``.](/reference/react/Suspense) If the background update caused by a new value suspends the UI, the user will not see the fallback. They will see the old deferred value until the data loads. +- `useDeferredValue` 与 [``](/reference/react/Suspense) 集成。如果由于新值引起的后台更新导致 UI 暂停,用户将不会看到 fallback 效果。他们将看到旧的延迟值,直到数据加载完成。 -- `useDeferredValue` does not by itself prevent extra network requests. +- `useDeferredValue` 本身并不能阻止额外的网络请求。 -- There is no fixed delay caused by `useDeferredValue` itself. As soon as React finishes the original re-render, React will immediately start working on the background re-render with the new deferred value. Any updates caused by events (like typing) will interrupt the background re-render and get prioritized over it. +- `useDeferredValue` 本身不会引起任何固定的延迟。一旦 React 完成原始的重新渲染,它会立即开始使用新的延迟值处理后台重新渲染。由事件(例如输入)引起的任何更新都会中断后台重新渲染,并被优先处理。 -- The background re-render caused by `useDeferredValue` does not fire Effects until it's committed to the screen. If the background re-render suspends, its Effects will run after the data loads and the UI updates. +- 由 `useDeferredValue` 引起的后台重新渲染在提交到屏幕之前不会触发 Effect。如果后台重新渲染被暂停,Effect 将在数据加载后和 UI 更新后运行。 --- -## Usage {/*usage*/} +## 用法 {/*usage*/} -### Showing stale content while fresh content is loading {/*showing-stale-content-while-fresh-content-is-loading*/} +### 在新内容加载期间显示旧内容。 {/*showing-stale-content-while-fresh-content-is-loading*/} -Call `useDeferredValue` at the top level of your component to defer updating some part of your UI. +在组件的顶层调用 `useDeferredValue` 来延迟更新 UI 的某些部分。 ```js [[1, 5, "query"], [2, 5, "deferredQuery"]] import { useState, useDeferredValue } from 'react'; @@ -74,25 +74,25 @@ function SearchPage() { } ``` -During the initial render, the deferred value will be the same as the value you provided. +在初始渲染期间,返回的 延迟值 与你提供的 相同。 -During updates, the deferred value will "lag behind" the latest value. In particular, React will first re-render *without* updating the deferred value, and then try to re-render with the newly received value in background. +在更新期间,延迟值 会“滞后于”最新的 。具体地说,React 首先会在不更新延迟值的情况下进行重新渲染,然后在后台尝试使用新接收到的值进行重新渲染。 -**Let's walk through an example to see when this is useful.** +**让我们通过一个例子来看看什么时候该使用它**。 -This example assumes you use one of Suspense-enabled data sources: +这个例子假设你使用了其中一个支持 `Suspense` 的数据源: -- Data fetching with Suspense-enabled frameworks like [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) and [Next.js](https://nextjs.org/docs/getting-started/react-essentials) -- Lazy-loading component code with [`lazy`](/reference/react/lazy) +- 使用支持 suspense 的框架进行数据获取,例如 [Relay](https://relay.dev/docs/guided-tour/rendering/loading-states/) 和 [Next.js](https://nextjs.org/docs/getting-started/react-essentials) +- 使用 [`lazy`](/reference/react/lazy) 懒加载组件代码 -[Learn more about Suspense and its limitations.](/reference/react/Suspense) +[了解更多有关 suspense 及其限制的信息](/reference/react/Suspense)。 -In this example, the `SearchResults` component [suspends](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading) while fetching the search results. Try typing `"a"`, waiting for the results, and then editing it to `"ab"`. The results for `"a"` get replaced by the loading fallback. +这个例子中,在获取搜索结果时,`SearchResults` 组件会 [suspend](/reference/react/Suspense#displaying-a-fallback-while-content-is-loading)。尝试输入 `"a"`,等待结果出现后,将其编辑为 `"ab"`。此时 `"a"` 的结果会被加载中的 fallback 替代。 @@ -134,11 +134,11 @@ export default function App() { ```js SearchResults.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// 注意:此组件使用了一种实验性 API +// 该 API 尚未在稳定版本的 React 中发布。 -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// 如果想找实际的例子,可以尝试一个 +// 已经集成了 suspense 的框架,比如 Relay 或 Next.js。 export default function SearchResults({ query }) { if (query === '') { @@ -159,8 +159,8 @@ export default function SearchResults({ query }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// 这是一个解决演示中的一个 bug 的临时实现。 +// TODO:待 bug 修复后替换为真正的实现。 function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -186,9 +186,9 @@ function use(promise) { ``` ```js data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// 注意:使用 suspense 进行数据获取的方式 +// 取决于与其配合使用的框架。 +// 缓存逻辑通常会在框架内部处理。 let cache = new Map(); @@ -208,7 +208,7 @@ async function getData(url) { } async function getSearchResults(query) { - // Add a fake delay to make waiting noticeable. + // 添加一个假延迟来让等待更加明显。 await new Promise(resolve => { setTimeout(resolve, 500); }); @@ -284,7 +284,7 @@ input { margin: 10px; } -A common alternative UI pattern is to *defer* updating the list of results and to keep showing the previous results until the new results are ready. Call `useDeferredValue` to pass a deferred version of the query down: +一个常见的备选 UI 模式是 **延迟** 更新结果列表,并继续显示之前的结果,直到新的结果准备好。调用 `useDeferredValue` 并将延迟版本的查询参数向下传递: ```js {3,11} export default function App() { @@ -304,9 +304,9 @@ export default function App() { } ``` -The `query` will update immediately, so the input will display the new value. However, the `deferredQuery` will keep its previous value until the data has loaded, so `SearchResults` will show the stale results for a bit. +`query` 会立即更新,所以输入框将显示新值。然而,`deferredQuery` 在数据加载完成前会保留以前的值,因此 `SearchResults` 将暂时显示旧的结果。 -Enter `"a"` in the example below, wait for the results to load, and then edit the input to `"ab"`. Notice how instead of the Suspense fallback, you now see the stale result list until the new results have loaded: +在下面的示例中,输入 `"a"`,等待结果加载完成,然后将输入框编辑为 `"ab"`。注意,现在你看到的不是 suspense fallback,而是旧的结果列表,直到新的结果加载完成: @@ -349,11 +349,11 @@ export default function App() { ```js SearchResults.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// 注意:此组件使用了一种实验性 API +// 该 API 尚未在稳定版本的 React 中发布。 -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// 如果想找实际的例子,可以尝试一个 +// 已经集成了 suspense 的框架,比如 Relay 或 Next.js。 export default function SearchResults({ query }) { if (query === '') { @@ -374,8 +374,8 @@ export default function SearchResults({ query }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// 这是一个解决演示中的一个 bug 的临时实现。 +// TODO:待 bug 修复后应该替换为真正的实现。 function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -401,9 +401,9 @@ function use(promise) { ``` ```js data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// 注意:使用 suspense 进行数据获取的方式 +// 取决于与其配合使用的框架。 +// 缓存逻辑通常会在框架内部处理。 let cache = new Map(); @@ -423,7 +423,7 @@ async function getData(url) { } async function getSearchResults(query) { - // Add a fake delay to make waiting noticeable. +// 添加一个假延迟来让等待更加明显。 await new Promise(resolve => { setTimeout(resolve, 500); }); @@ -501,25 +501,25 @@ input { margin: 10px; } -#### How does deferring a value work under the hood? {/*how-does-deferring-a-value-work-under-the-hood*/} +#### 如何在内部实现延迟值? {/*how-does-deferring-a-value-work-under-the-hood*/} -You can think of it as happening in two steps: +你可以将其看成两个步骤: -1. **First, React re-renders with the new `query` (`"ab"`) but with the old `deferredQuery` (still `"a")`.** The `deferredQuery` value, which you pass to the result list, is *deferred:* it "lags behind" the `query` value. +1. **首先,React 会使用新的 `query` 值(`"ab"`)和旧的 `deferredQuery` 值(仍为 `"a"`)重新渲染。** 传递给结果列表的 `deferredQuery` 值是**延迟**的,它“滞后于” `query` 值。 -2. **In background, React tries to re-render with *both* `query` and `deferredQuery` updated to `"ab"`.** If this re-render completes, React will show it on the screen. However, if it suspends (the results for `"ab"` have not loaded yet), React will abandon this rendering attempt, and retry this re-render again after the data has loaded. The user will keep seeing the stale deferred value until the data is ready. +2. **在后台,React 尝试重新渲染,并将 `query` 和 `deferredQuery` 两个值都更新为 `"ab"`。** 如果此次重新渲染完成,React 将在屏幕上显示它。但是,如果它 suspense(即 `"ab"` 的结果尚未加载),React 将放弃这次渲染,并在数据加载后再次尝试重新渲染。用户将一直看到旧的延迟值,直到数据准备就绪。 -The deferred "background" rendering is interruptible. For example, if you type into the input again, React will abandon it and restart with the new value. React will always use the latest provided value. +被推迟的“后台”渲染是可中断的。例如,如果你再次在输入框中输入,React 将会中断渲染,并从新值开始重新渲染。React 总是使用最新提供的值。 -Note that there is still a network request per each keystroke. What's being deferred here is displaying results (until they're ready), not the network requests themselves. Even if the user continues typing, responses for each keystroke get cached, so pressing Backspace is instant and doesn't fetch again. +注意,每次按键仍会发起一个网络请求。这里延迟的是显示结果(直到它们准备就绪),而不是网络请求本身。即使用户继续输入,每个按键的响应都会被缓存,所以按下 Backspace 键是瞬时的,不会再次获取数据。 --- -### Indicating that the content is stale {/*indicating-that-the-content-is-stale*/} +### 表明内容已过时 {/*indicating-that-the-content-is-stale*/} -In the example above, there is no indication that the result list for the latest query is still loading. This can be confusing to the user if the new results take a while to load. To make it more obvious to the user that the result list does not match the latest query, you can add a visual indication when the stale result list is displayed: +在上面的示例中,当最新的查询结果仍在加载时,没有任何提示。如果新的结果需要一段时间才能加载完成,这可能会让用户感到困惑。为了更明显地告知用户结果列表与最新查询不匹配,你可以在显示旧的查询结果时添加一个视觉提示: ```js {2}
``` -With this change, as soon as you start typing, the stale result list gets slightly dimmed until the new result list loads. You can also add a CSS transition to delay dimming so that it feels gradual, like in the example below: +有了上面这段代码,当你开始输入时,旧的结果列表会略微变暗,直到新的结果列表加载完毕。你也可以添加 CSS 过渡来延迟变暗的过程,让用户感受到一种渐进式的过渡,就像下面的例子一样: @@ -578,11 +578,11 @@ export default function App() { ```js SearchResults.js hidden import { fetchData } from './data.js'; -// Note: this component is written using an experimental API -// that's not yet available in stable versions of React. +// 注意:此组件使用了一种实验性 API +// 该 API 尚未在稳定版本的 React 中发布。 -// For a realistic example you can follow today, try a framework -// that's integrated with Suspense, like Relay or Next.js. +// 如果想找实际的例子,可以尝试一个 +// 已经集成了 suspense 的框架,比如 Relay 或 Next.js。 export default function SearchResults({ query }) { if (query === '') { @@ -603,8 +603,8 @@ export default function SearchResults({ query }) { ); } -// This is a workaround for a bug to get the demo running. -// TODO: replace with real implementation when the bug is fixed. +// 这是一个解决演示中的一个 bug 的临时实现。 +// TODO:待 bug 修复后应该替换为真正的实现。 function use(promise) { if (promise.status === 'fulfilled') { return promise.value; @@ -630,9 +630,9 @@ function use(promise) { ``` ```js data.js hidden -// Note: the way you would do data fetching depends on -// the framework that you use together with Suspense. -// Normally, the caching logic would be inside a framework. +// 注意:使用 suspense 进行数据获取的方式 +// 取决于与其配合使用的框架。 +// 缓存逻辑通常会在框架内部处理。 let cache = new Map(); @@ -652,7 +652,7 @@ async function getData(url) { } async function getSearchResults(query) { - // Add a fake delay to make waiting noticeable. +// 添加一个假延迟来让等待更加明显。 await new Promise(resolve => { setTimeout(resolve, 500); }); @@ -730,11 +730,11 @@ input { margin: 10px; } --- -### Deferring re-rendering for a part of the UI {/*deferring-re-rendering-for-a-part-of-the-ui*/} +### 延迟渲染 UI 的某些部分 {/*deferring-re-rendering-for-a-part-of-the-ui*/} -You can also apply `useDeferredValue` as a performance optimization. It is useful when a part of your UI is slow to re-render, there's no easy way to optimize it, and you want to prevent it from blocking the rest of the UI. +你还可以将 `useDeferredValue` 作为性能优化的手段。当你的 UI 某个部分重新渲染很慢、没有简单的优化方法,同时你又希望避免它阻塞其他 UI 的渲染时,使用 `useDeferredValue` 很有帮助。 -Imagine you have a text field and a component (like a chart or a long list) that re-renders on every keystroke: +想象一下,你有一个文本框和一个组件(例如图表或长列表),在每次按键时都会重新渲染: ```js function App() { @@ -748,7 +748,7 @@ function App() { } ``` -First, optimize `SlowList` to skip re-rendering when its props are the same. To do this, [wrap it in `memo`:](/reference/react/memo#skipping-re-rendering-when-props-are-unchanged) +首先,我们可以优化 `SlowList`,使其在 props 不变的情况下跳过重新渲染。只需将其 [用 `memo` 包裹](/reference/react/memo#skipping-re-rendering-when-props-are-unchanged) 即可: ```js {1,3} const SlowList = memo(function SlowList({ text }) { @@ -756,9 +756,9 @@ const SlowList = memo(function SlowList({ text }) { }); ``` -However, this only helps if the `SlowList` props are *the same* as during the previous render. The problem you're facing now is that it's slow when they're *different,* and when you actually need to show different visual output. +然而,这仅在 `SlowList` 的 props 与上一次的渲染时相同才有用。你现在遇到的问题是,当这些 props **不同** 时,并且实际上需要展示不同的视觉输出时,页面会变得很慢。 -Concretely, the main performance problem is that whenever you type into the input, the `SlowList` receives new props, and re-rendering its entire tree makes the typing feel janky. In this case, `useDeferredValue` lets you prioritize updating the input (which must be fast) over updating the result list (which is allowed to be slower): +具体而言,主要的性能问题在于,每次你输入内容时,`SlowList` 都会接收新的 props,并重新渲染整个树结构,这会让输入感觉很卡顿。使用 `useDeferredValue` 能够优先更新输入框(必须快速更新),而不是更新结果列表(可以更新慢一些),从而缓解这个问题: ```js {3,7} function App() { @@ -773,13 +773,13 @@ function App() { } ``` -This does not make re-rendering of the `SlowList` faster. However, it tells React that re-rendering the list can be deprioritized so that it doesn't block the keystrokes. The list will "lag behind" the input and then "catch up". Like before, React will attempt to update the list as soon as possible, but will not block the user from typing. +这并没有让 `SlowList` 的重新渲染变快。然而,它告诉 React 可以将列表的重新渲染优先级降低,这样就不会阻塞按键输入。列表的更新会“滞后”于输入,然后“追赶”上来。与之前一样,React 会尽快更新列表,但不会阻塞用户输入。 - + -#### Deferred re-rendering of the list {/*deferred-re-rendering-of-the-list*/} +#### 延迟列表的重新渲染 {/*deferred-re-rendering-of-the-list*/} -In this example, each item in the `SlowList` component is **artificially slowed down** so that you can see how `useDeferredValue` lets you keep the input responsive. Type into the input and notice that typing feels snappy while the list "lags behind" it. +在这个例子中,`SlowList` 组件中的每个 item 都被 **故意减缓了渲染速度**,这样你就可以看到 `useDeferredValue` 是如何让输入保持响应的。当你在输入框中输入时,你会发现输入很灵敏,而列表的更新会稍有延迟。 @@ -803,7 +803,7 @@ export default function App() { import { memo } from 'react'; const SlowList = memo(function SlowList({ text }) { - // Log once. The actual slowdown is inside SlowItem. + // 仅打印一次。实际的减速是在 SlowItem 组件内部。 console.log('[ARTIFICIALLY SLOW] Rendering 250 '); let items = []; @@ -820,7 +820,7 @@ const SlowList = memo(function SlowList({ text }) { function SlowItem({ text }) { let startTime = performance.now(); while (performance.now() - startTime < 1) { - // Do nothing for 1 ms per item to emulate extremely slow code + // 每个 item 暂停 1ms,模拟极其缓慢的代码 } return ( @@ -853,11 +853,11 @@ export default SlowList; -#### Unoptimized re-rendering of the list {/*unoptimized-re-rendering-of-the-list*/} +#### 列表的未优化重新渲染 {/*unoptimized-re-rendering-of-the-list*/} -In this example, each item in the `SlowList` component is **artificially slowed down**, but there is no `useDeferredValue`. +在这个例子中,`SlowList` 组件中的每个 item 都被 **故意减缓了渲染速度**,但这次没有使用 `useDeferredValue`。 -Notice how typing into the input feels very janky. This is because without `useDeferredValue`, each keystroke forces the entire list to re-render immediately in a non-interruptible way. +注意,输入框的输入感觉非常卡顿。这是因为没有使用 `useDeferredValue`,每次按键都会立即强制整个列表以不可中断的方式进行重新渲染。 @@ -880,7 +880,7 @@ export default function App() { import { memo } from 'react'; const SlowList = memo(function SlowList({ text }) { - // Log once. The actual slowdown is inside SlowItem. + // 仅打印一次。实际的减速是在 SlowItem 组件内部。 console.log('[ARTIFICIALLY SLOW] Rendering 250 '); let items = []; @@ -897,7 +897,7 @@ const SlowList = memo(function SlowList({ text }) { function SlowItem({ text }) { let startTime = performance.now(); while (performance.now() - startTime < 1) { - // Do nothing for 1 ms per item to emulate extremely slow code + // 每个 item 暂停 1ms,模拟极其缓慢的代码 } return ( @@ -934,25 +934,25 @@ export default SlowList; -This optimization requires `SlowList` to be wrapped in [`memo`.](/reference/react/memo) This is because whenever the `text` changes, React needs to be able to re-render the parent component quickly. During that re-render, `deferredText` still has its previous value, so `SlowList` is able to skip re-rendering (its props have not changed). Without [`memo`,](/reference/react/memo) it would have to re-render anyway, defeating the point of the optimization. +这个优化需要将 `SlowList` 包裹在 [`memo`](/reference/react/memo) 中。这是因为每当 `text` 改变时,React 需要能够快速重新渲染父组件。在重新渲染期间,`deferredText` 仍然保持着之前的值,因此 `SlowList` 可以跳过重新渲染(它的 props 没有改变)。如果没有 [`memo`](/reference/react/memo),`SlowList` 仍会重新渲染,这将使优化失去意义。 -#### How is deferring a value different from debouncing and throttling? {/*how-is-deferring-a-value-different-from-debouncing-and-throttling*/} +#### 延迟一个值与防抖和节流之间有什么不同? {/*how-is-deferring-a-value-different-from-debouncing-and-throttling*/} -There are two common optimization techniques you might have used before in this scenario: +在上述的情景中,你可能会使用这两种常见的优化技术: -- *Debouncing* means you'd wait for the user to stop typing (e.g. for a second) before updating the list. -- *Throttling* means you'd update the list every once in a while (e.g. at most once a second). +- **防抖** 是指在用户停止输入一段时间(例如一秒钟)之后再更新列表。 +- **节流** 是指每隔一段时间(例如最多每秒一次)更新列表。 -While these techniques are helpful in some cases, `useDeferredValue` is better suited to optimizing rendering because it is deeply integrated with React itself and adapts to the user's device. +虽然这些技术在某些情况下是有用的,但 `useDeferredValue` 更适合优化渲染,因为它与 React 自身深度集成,并且能够适应用户的设备。 -Unlike debouncing or throttling, it doesn't require choosing any fixed delay. If the user's device is fast (e.g. powerful laptop), the deferred re-render would happen almost immediately and wouldn't be noticeable. If the user's device is slow, the list would "lag behind" the input proportionally to how slow the device is. +与防抖或节流不同,`useDeferredValue` 不需要选择任何固定延迟时间。如果用户的设备很快(比如性能强劲的笔记本电脑),延迟的重渲染几乎会立即发生并且不会被察觉。如果用户的设备较慢,那么列表会相应地“滞后”于输入,滞后的程度与设备的速度有关。 -Also, unlike with debouncing or throttling, deferred re-renders done by `useDeferredValue` are interruptible by default. This means that if React is in the middle of re-rendering a large list, but the user makes another keystroke, React will abandon that re-render, handle the keystroke, and then start rendering in background again. By contrast, debouncing and throttling still produce a janky experience because they're *blocking:* they merely postpone the moment when rendering blocks the keystroke. +此外,与防抖或节流不同,`useDeferredValue` 执行的延迟重新渲染默认是可中断的。这意味着,如果 React 正在重新渲染一个大型列表,但用户进行了另一次键盘输入,React 会放弃该重新渲染,先处理键盘输入,然后再次开始在后台渲染。相比之下,防抖和节流仍会产生不顺畅的体验,因为它们是阻*的:它们仅仅是将渲染阻塞键盘输入的时刻推迟了。 -If the work you're optimizing doesn't happen during rendering, debouncing and throttling are still useful. For example, they can let you fire fewer network requests. You can also use these techniques together. +如果你要优化的工作不是在渲染期间发生的,那么防抖和节流仍然非常有用。例如,它们可以让你减少网络请求的次数。你也可以同时使用这些技术。