在 egghead.io 上观看 "启用 React 并发模式"(我的 "使用暂停来简化你的异步 UI"课程的一部分)。
React新的并发模式刚刚在实验发布频道发布。 这是多年研究的结果,而且显示了这一点。如果你想了解更多关于它为什么这么酷,一定要看Dan Abramov在JSIceland的演讲。 人们已经开始使用它,并看到一些很好的perf wins开箱即用。
综上所述,请记住这是实验性的。实验性的发布渠道并不支持semver(所以依赖它的代码可能会意外中断),而且肯定会有bug。但早期的实验对许多人来说是有希望的,我建议你在自己的应用程序中尝试一下。
步骤1
把它安装好。
首先,要启用并发模式,你需要有一个支持该模式的React版本。在写这篇文章的时候,React和React DOM的版本是16.11.0 ,不支持并发模式。所以我们需要安装experimental 版本。
npm install react@experimental react-dom@experimental
# or: yarn add react@experimental react-dom@experimental
第2步
确保你的应用程序可以工作,而不需要改变任何其他东西。
运行你的应用程序,运行你的构建,运行你的测试/类型检查。如果控制台中出现了以前没有的新错误,那么这些可能是React的bug,你应该尝试做一个最小的重现(最好是在codesandbox中),并在React repo上开一个新问题。
通常我们会跳过这一步,但我认为重要的是,如果有问题,你要确保知道这些问题是从哪一步开始的!我想说的是,这是一个很好的建议😉
第3步
启用并发模式。
在你的项目的入口文件中,你可能有像这样的东西:
import * as React from 'react'
import ReactDOM from 'react-dom'
import App from './app'
const rootEl = document.getElementById('root')
ReactDOM.render(<App />, rootEl)
要启用并发模式,你将使用一个新的createRoot API(注意unstable_ 的前缀):
import * as React from 'react'
import ReactDOM from 'react-dom'
import App from './app'
const rootEl = document.getElementById('root')
// ReactDOM.render(<App />, rootEl)
const root = ReactDOM.unstable_createRoot(rootEl)
root.render(<App />)
就是这样。
第4步
确保你的应用程序可以工作,而不需要改变任何其他东西。
运行你的应用程序,运行你的构建,运行你的测试/类型检查。如果控制台中出现了以前没有的新错误,那么这些可能是React的bug,你应该尝试做一个最小的复制(最好是在codesandbox中),并在React repo上开一个新问题。
如果这看起来很熟悉,那是因为我从第2步复制/粘贴了它 😂
然而,在这种情况下,如果事情被破坏了,或者你在控制台有新的错误。这可能是因为你的应用程序中的代码使用了并发模式不支持的功能(如String Refs,Legacy Context,或findDOMNode )。
另外请注意,所有带有unsafe_ 前缀的生命周期方法现在实际上都是不安全的,你使用这些方法会遇到错误。
第5步
试用并发模式。并发模式对我们来说有两个主要的功能:
- 时间切分
- 暂停一切异步的工作
如果你的应用中有一些用户交互,你知道它很慢,那就试试吧,如果它不那么糟糕了,那就是时间切分在起作用(观看上面链接的Dan的演讲,了解更多这方面的内容)。
你可以尝试将你的一个异步交互重构为悬念,或者只是尝试在你的应用中的某个地方添加这个。
function SuspenseDemo() {
const [greetingResource, setGreetingResource] = React.useState(null)
const [startTransition, isPending] = React.unstable_useTransition()
function handleSubmit(event) {
event.preventDefault()
const name = event.target.elements.nameInput.value
startTransition(() => {
setGreetingResource(createGreetingResource(name))
})
}
return (
<div>
<strong>Suspense Demo</strong>
<form onSubmit={handleSubmit}>
<label htmlFor="nameInput">Name</label>
<input id="nameInput" />
<button type="submit">Submit</button>
</form>
<ErrorBoundary>
<React.Suspense fallback={<p>loading greeting</p>}>
<Greeting greetingResource={greetingResource} isPending={isPending} />
</React.Suspense>
</ErrorBoundary>
</div>
)
}
function Greeting({greetingResource, isPending}) {
return (
<p style={{opacity: isPending ? 0.4 : 1}}>
{greetingResource ? greetingResource.read() : 'Please submit a name'}
</p>
)
}
// 🐨 make this function do something else. Like an HTTP request or something
function getGreeting(name) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Hello ${name}!`)
// 🐨 try rejecting instead... (make sure to comment out the resolve call)
// reject(new Error(`Oh no. Could not load greeting for ${name}`))
}, 1500) // 🐨 play with this number a bit
})
}
// 🚨 This should NOT be copy/pasted for production code and is only here
// for experimentation purposes. The API for suspense (currently throwing a
// promise) is likely to change before suspense is officially released.
function createGreetingResource(name) {
let status = 'pending'
let result
let suspender = getGreeting(name).then(
greeting => {
status = 'success'
result = greeting
},
error => {
status = 'error'
result = error
},
)
return {
read() {
if (status === 'pending') throw suspender
if (status === 'error') throw result
if (status === 'success') return result
},
}
}
class ErrorBoundary extends React.Component {
state = {error: null}
static getDerivedStateFromError(error) {
return {error}
}
componentDidCatch() {
// log the error to the server
}
tryAgain = () => this.setState({error: null})
render() {
return this.state.error ? (
<div>
There was an error. <button onClick={this.tryAgain}>try again</button>
<pre style={{whiteSpace: 'normal'}}>{this.state.error.message}</pre>
</div>
) : (
this.props.children
)
}
}
我发现的一点是,suspense API是相当低级的,所以需要大量的代码来使其良好运行。但很酷的是,这些都是原子性的功能,在一个抽象中工作得非常好,可以很容易地共享。因此,一旦你得到了这个抽象,你就是金子。这是很好的。
第6步
撤销你所有的修改。
重新安装你之前安装的最后一个稳定版本,并恢复你之前的旧ReactDOM.render 。并发模式是实验性的,即使看起来没有问题,像React这样的基础性的实验性软件的运输是不明智的。React文档甚至建议,根据你的应用程序的大小和你所使用的第三方库,你可能永远无法运送并发模式(Facebook目前没有计划在旧Facebook.com上启用并发模式)。
还请记住,我们作为一个社区刚刚开始玩这个东西,所以在不同方法的权衡方面仍然有很多未知数。这是一个令人兴奋的时刻。但如果你重视稳定性,那么也许可以暂时假装并发模式和悬念不存在。
第7步
启用严格模式。
没有通过严格模式的应用程序不可能在并发模式下运行良好。 因此,如果你想努力在你的应用程序上启用并发模式,那么就启用严格模式。严格模式的一个好处是(与并发模式不同),它是可以逐步采用的。因此,你可以只将严格模式应用于你的代码库中你知道符合要求的部分,然后随着时间的推移迭代到完全支持。
请在我的博客上阅读更多信息:如何启用 React 严格模式。
总结
我真的很期待数据获取的并发模式和暂停的稳定发布。当框架和库利用这些新功能时,将会更酷。就像React Hooks对React生态系统的影响一样,我认为并发模式对开发者的体验和终端用户的影响更大。
享受实验吧