React 18 正式发布了
早上上班打开 React
官网 发现React 18
正式发布了,看了下更新记录,干货满满呀。
一. 放弃对 Internet Explorer
的支持
React 18
将放弃对 Internet Explorer
的支持,IE
将于 2022 年 6 月 15 日停止维护。 React 18
中引入的新功能是使用现代浏览器功能构建的,例如无法在 IE
中充分填充的微任务。
如果需要支持 Internet Explorer
,建议继续使用 React 17
。
二. 新功能
1. 并发渲染
这个之前已经爆料好多次了,并发本身不是一个特性。这是一种新的幕后机制,使 React
能够同时准备多个版本的 UI。可以将并发视为一个实现细节——它之所以有价值,是因为它解锁了一些特性。React
在其内部实现中使用了复杂的技术,例如优先级队列和多重缓冲。但是不会在公共 API 中的任何地方看到这些概念。
2. 自动批处理
批处理是 React
将多个状态更新分组到一个重新渲染中以获得更好的性能。如果没有自动批处理,只能在 React
事件处理程序中批处理更新。默认情况下,Promise
、setTimeout
、本机事件处理程序或任何其他事件内部的更新不会在 React
中批处理。使用自动批处理,这些更新将自动批处理。
1 | // 在 React 18 之前,只有 React 事件被批处理 |
2 | |
3 | function handleClick() { |
4 | setCount(c => c + 1) |
5 | setFlag(f => !f) |
6 | // React 只会在最后重新渲染一次(这就是批处理!) |
7 | } |
8 | |
9 | setTimeout(() => { |
10 | setCount(c => c + 1) |
11 | setFlag(f => !f) |
12 | // React 将渲染两次,每次状态更新一次(无批处理) |
13 | }, 1000) |
这是一项重大更改,这会减少工作渲染,从而提高应用程序的性能。要退出自动批处理,可以使用 flushSync
:
1 | import { flushSync } from 'react-dom' |
2 | |
3 | function handleClick() { |
4 | flushSync(() => { |
5 | setCounter(c => c + 1) |
6 | }) |
7 | |
8 | // React 现在已经更新了 DOM |
9 | flushSync(() => { |
10 | setFlag(f => !f) |
11 | }) |
12 | // React 现在已经更新了 DOM |
13 | } |
3. 过渡
过渡是 React 18 中引入的一个新的并发特性,用于区分紧急和非紧急更新。它允许您将更新标记为过渡。对应新增的 api
React.startTransition
和 React.useTransition
4. 新的 Suspense
功能
如果组件树的一部分尚未准备好显示,Suspense
允许您以声明方式指定组件树的加载状态:
1 | <Suspense fallback={<Spinner />}> |
2 | <Comments /> |
3 | </Suspense> |
Suspense
使 UI 加载状态
成为 React
编程模型中一流的声明性概念。这可以在它之上构建更高级别的功能。在 React 18
中,在服务器上添加了对Suspense
的支持,并使用并发渲染特性扩展了它的功能。
5. render
api 变更
createRoot
render
替换 原来的 ReactDOM.render
,createRoot
现在从 react-dom/client
上导出。
原来的
1 | import { render } from 'react-dom' |
2 | const container = document.getElementById('app') |
3 | render(<App tab='home' />, container) |
现在的
1 | import { createRoot } from 'react-dom/client' |
2 | const container = document.getElementById('app') |
3 | const root = createRoot(container) |
4 | root.render(<App tab='home' />) |
可以使用unmount
以下命令卸载 root。
1 | root.unmount() |
6. 服务端 api 变更
这些新的 API
现在从 react-dom/server
上导出并完全支持流式传输 Suspense
renderToPipeableStream
: 用于 Node 环境中的流式传输。
renderToReadableStream
:适用于现代边缘运行时环境,例如 Deno
和 Cloudflare worker
。
现有 renderToString
方法继续有效,但不鼓励使用。
renderToNodeStream
: 已弃用
以下 API
将继续工作,但对 Suspense
的支持有限:
renderToString
和 renderToStaticMarkup
renderToStaticNodeStream
: 此 API 将继续用于呈现电子邮件
7. 新的严格模式行为
8. 新增 hooks
useId
useId
是一个新的钩子,用于在客户端和服务器上生成唯一 ID,同时避免水合不匹配。它主要用于与需要唯一 ID 的可访问性 API 集成的组件库。这解决了 React 17
及更低版本中已经存在的问题,但在 React 18
中更为重要,因为新的流式服务器渲染器如何无序交付 HTML。
useTransition
useTransition
和 startTransition
让您将一些状态更新标记为不紧急。默认情况下,其他状态更新被认为是紧急的。React
将允许紧急状态更新(例如,更新文本输入)以中断非紧急状态更新(例如,呈现搜索结果列表) 。
useDeferredValue
useDeferredValue
让您推迟重新渲染树的非紧急部分。它类似于去抖动,但与之相比有一些优点。没有固定的时间延迟,因此 React
将在第一次渲染反映在屏幕上后立即尝试延迟渲染。延迟渲染是可中断的,不会阻止用户输入。
useSyncExternalStore
useSyncExternalStore
是一个新的钩子,它允许外部存储通过强制对存储的更新同步来支持并发读取。在实现对外部数据源的订阅时,它消除了对 useEffect
的需要,并且推荐用于任何与 React
外部状态集成的库。
useInsertionEffect
useInsertionEffect 是一个新的钩子,它允许 CSS-in-JS
库解决在渲染中注入样式的性能问题。除非您已经构建了CSS-in-JS
库,否则我们不希望您使用它。这个钩子将在 DOM 发生变异之后运行,但在布局效果读取新布局之前。这解决了在 React 17
及更低版本中已经存在的问题,但在 React 18
中更为重要,因为 React
在并发渲染期间屈服于浏览器,使其有机会重新计算布局
三. 已弃用 api
1. react-dom:ReactDOM.render
已弃用
在 React 17
下运行的应用程序会警告。
2. react-dom:ReactDOM.hydrate
已弃用。
在 React 17
下运行的应用程序会警告。
3. react-dom:ReactDOM.unmountComponentAtNode
已弃用。
4. react-dom:ReactDOM.renderSubtreeIntoContainer
已弃用。
5. react-dom/server:ReactDOMServer.renderToNodeStream
已弃用。
四.其他变化
1. 组件现在可以渲染 undefined
undefined
如果您从组件返回,React
不再发出警告。这使得允许的组件返回值与组件树中间允许的值一致。建议使用 linter
来防止忘记 return JSX
之前的语句等错误。
2. 在测试中,act 警告现在是可选的
在测试中,act 警告现在是可选的:如果您正在运行端到端测试,则 act 警告是不必要的。我们引入了一种选择加入机制,因此您只能在有用且有益的单元测试中启用它们。
3. 组件为卸载时不在警告 setState
以前,当您调用未安装的组件时,React
会警告内存泄漏。此警告是为订阅添加的,但人们主要在设置状态很好的情况下遇到它,并且变通方法会使代码变得更糟。已删除此警告。
4. 不抑制控制台日志
当您使用严格模式时,React
会渲染每个组件两次,以帮助您发现意外的副作用。在 React 17
中,抑制了两个渲染之一的控制台日志,以使日志更易于阅读。为了回应社区对此令人困惑的反馈,已经删除了抑制。相反,如果你安装了 React DevTools
,第二个日志的渲染将显示为灰色,并且会有一个选项(默认关闭)来完全抑制它们。
5. 改进的内存使用
React
现在会在卸载时清理更多内部字段,从而降低应用程序代码中可能存在的未修复内存泄漏的影响。
6.服务端渲染
renderToString
:
在服务器上挂起时将不再出错。相反,它将为最近的<Suspense>
边界发出回退HTML
,然后重试在客户端上呈现相同的内容。仍然建议您切换到流式 API,例如 renderToPipeableStreamor
renderToReadableStream
。
renderToStaticMarkup
:
在服务器上挂起时将不再出错。相反,它将为最近的