React 18的实验性并发模式的一部分是一个新的功能,叫做startTransition
,它可以防止昂贵的UI渲染被立即执行。
为了理解我们为什么需要这个功能,请记住,强迫昂贵的UI渲染立即完成会阻止较轻和较紧急的UI渲染及时渲染。这可能会使那些需要从紧急的UI渲染中获得即时响应的用户感到沮丧。
一个紧急UI渲染的例子是在一个搜索栏中打字。当你打字时,你希望看到你的打字表现出来并立即开始搜索。如果应用程序冻结了,搜索停止了,你就会感到很沮丧。其他昂贵的UI渲染会使整个应用程序陷入困境,包括你的轻型UI渲染,这些渲染应该是快速的(比如在你输入时看到搜索结果)。
在开发你的React应用时,你可以通过debouncing或throttling来避免这个问题。不幸的是,使用debouncing或throttling仍然会导致应用程序变得没有反应。
startTransition
允许你将应用程序中的某些更新标记为非紧急,因此它们被暂停,而更紧急的更新被优先处理。这使你的应用程序感觉更快,并可以减少你的应用程序中渲染非严格必要项目的负担。因此,无论你在渲染什么,你的应用程序仍然在对用户的输入做出响应。
在这篇文章中,我们将学习如何在你的React应用中使用startTransition
,以便延迟非紧急的UI更新,避免阻塞紧急的UI更新。有了这个功能,你可以在短时间内将你缓慢的React应用程序转换成一个响应式的应用程序。
在我们开始之前,请注意React 18在撰写本文时仍处于alpha阶段,所以startTransition
还不是稳定版本的一部分。
开始使用React 18
在开始本教程之前,请确保你具备以下条件。
- 有关React的工作知识
- 在你的机器上安装了Node.js
让我们先用create-react-app创建一个React项目。
$ npx create-react-app starttransition_demo
上面的命令创建了一个React项目,使用的是React的最新稳定版本,也就是17版。我们需要使用React 18。进入项目目录内部,删除node_modules
目录。
$ cd starttransition_demo/
$ rm -rf node_modules
在Windows上,你必须使用一个不同的命令来删除该目录。删除该目录后,编辑package.json
。找到这些行。
"react": "^17.0.2",
"react-dom": "^17.0.2",
然后,将React的版本从17改为alpha。
"react": "alpha",
"react-dom": "alpha",
最后,用yarn
安装库。
$ yarn install
为了确保你已经安装了React 18,你可以像这样从node_modules
目录中检查它。
$ grep version node_modules/react/package.json
"version": "18.0.0-alpha-6ecad79cc-20211006",
在Windows上,你可以直接打开该文件。
运行服务器以确保你可以运行React 18应用程序。
yarn start
在你的浏览器中打开http://localhost:3000。你应该看到熟悉的React项目的默认页面,有一个旋转的React标志。
启用并发模式
默认情况下,我们的React项目并不支持并发模式。我们需要通过以不同的方式渲染根React节点来启用它。
打开src/index.js
。你可以看到,我们用render
静态方法渲染根节点,该方法来自ReactDOM
。
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
为了启用并发模式,我们需要先创建根节点,然后使用该实例的render
方法。把上面的行改为下面的行。
const container = document.getElementById('root')
const root = ReactDOM.createRoot(container);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
注意来自ReactDOM
的createRoot
方法。这将创建一个根节点。
设置一个测试环境
首先,让我们创建一个具有轻度UI渲染和重度UI渲染的React应用程序。打开src/App.js
。你可以看到App
函数的定义显示了一个React标志、一个p
标签和一个链接。
用下面的代码替换App
函数。
function App() {
const [search_text, setSearchText] = useState("");
const [search_result, setSearchResult] = useState();
const handleChange = e => {
setSearchText(e.target.value);
};
useEffect(() => {
if (search_text==="") {
setSearchResult(null);
} else {
const rows = Array.from(Array(5000), (_, index) => {
return (
<div key={index}>
<img src={logo} className="App-logo" alt="logo" />
<div>{index + 1}. {search_text}</div>
</div>
);
});
const list = <div>{rows}</div>;
setSearchResult(list);
}
}, [search_text]);
return (
<div className="App">
<header className="App-header">
<div className="SearchEngine">
<div className="SearchInput">
<input type="text" value={search_text} onChange={handleChange} />
</div>
<div className="SearchResult">
{search_result}
</div>
</div>
</header>
</div>
);
}
你需要导入useEffect
和useState
。把这一行放在文件的顶部。
import {useState, useEffect } from 'react';
在这里,我们正在创建应用程序的用户界面,由两部分组成:搜索输入和搜索结果。
因为输入法有一个回调,当你在输入法上输入文本时,该文本会作为参数传给setSearchText
,以使用useState
钩子更新search_text
的值。然后,搜索结果就显示出来了。对于这个演示,结果是5000行,其中每一行由一个旋转的React标识和相同的搜索查询文本组成。
我们轻快而直接的UI渲染是搜索输入及其文本。当你在搜索输入上键入文本时,文本应该立即出现。然而,显示5000个React标识和搜索文本是一个昂贵的UI渲染。
让我们看一个例子;试着在我们新的React应用程序中快速输入 "我非常喜欢React"。当你输入 "I "时,应用程序立即在搜索输入上渲染 "I "这个文本。然后,它渲染了5000行。这需要很长的时间,这揭示了我们的渲染问题。React应用程序不能立即渲染全部文本。昂贵的UI渲染使轻型UI渲染也变得缓慢。
你可以自己在应用程序上试试,网址是http://localhost:3000。你会看到一个搜索输入。我也设置了一个演示应用程序。
我们想要的是让昂贵的UI渲染在加载时不要把轻型UI渲染拖到泥里。它们应该被分开,这就是startTransition
。
使用startTransition
让我们看看当我们导入startTransition
,会发生什么。你的顶行导入应该是这样的。
import {useState, useEffect, startTransition} from 'react';
然后,把昂贵的UI渲染包在这个函数中。将setSearchResult(list)
改为下面的代码。
startTransition(() => {
setSearchResult(list);
});
现在,你可以再次测试这个应用程序。当你在搜索输入中输入东西时,文本会立即被渲染出来。在你停止后(或几秒钟过去后),React应用会渲染搜索结果。
如果你想在等待昂贵的UI渲染完成时,在搜索结果上显示一些东西,怎么办?你可能想显示一个进度条,给用户一个即时的反馈,让他们知道这个应用正在处理他们的请求。
为此,我们可以使用来自useTransition
钩子的isPending
变量。
首先,将文件顶部的导入行改为下面的代码。
import {useState, useEffect, useTransition} from 'react';
从useTransition
钩子中提取isPending
和startTransition
。把下面的代码放在App
函数内的第一行。
const [isPending, startTransition] = useTransition();
接下来,将<div className="SearchResult">
的内容改为下面的代码。
{isPending && <div><br /><span>Loading...</span></div>}
{!isPending && search_result}
现在,当你在搜索输入框上快速输入文字时,会先显示加载指示器。
结论
通过startTransition
,你可以通过分离即时UI渲染和非即时UI渲染来使React应用变得流畅和反应性。通过将所有非紧急的UI渲染放在startTransition
方法内,你的应用程序的使用将更加令人满意。
我们还涵盖了使用isPending
变量来表示转换的状态,以备你想给用户提供反馈。
你可以在这里获得startTransition
演示应用程序的完整代码。你也可以尽情地试验该应用程序的演示。希望这些知识在你构建下一个React应用时对你有用。确保应用程序将是顺利的!
The postGetting started withstartTransition
in React 18appeared first onLogRocket Blog.