一、前言
本文基于开源项目:
React18在几个小时前发布了release,我们一起来看看。
重大变化抢先看:自动批处理、严格模式、一致的 useEffect 计时、更严格的水合错误、挂起树总是一致的、带有悬念的布局效果、新的 JS 环境要求。
二、新特性
React
useId
是一个新的钩子,用于在客户端和服务器上生成唯一 ID,同时避免水合不匹配。它主要用于与需要唯一 ID 的可访问性 API 集成的组件库。这解决了 React 17 及更低版本中已经存在的问题,但在 React 18 中更为重要,因为新的流式服务器渲染器如何无序交付 HTML。startTransition
并useTransition
让您将一些状态更新标记为不紧急。默认情况下,其他状态更新被认为是紧急的。React 将允许紧急状态更新(例如,更新文本输入)以中断非紧急状态更新(例如,呈现搜索结果列表)。useDeferredValue
让您推迟重新渲染树的非紧急部分。它类似于去抖动,但与之相比有一些优点。没有固定的时间延迟,因此 React 将在第一次渲染反映在屏幕上后立即尝试延迟渲染。延迟渲染是可中断的,不会阻止用户输入。useSyncExternalStore
是一个新的钩子,它允许外部存储通过强制对存储的更新同步来支持并发读取。它消除了useEffect
在实现对外部数据源的订阅时的需要,并且推荐用于任何与 React 外部状态集成的库。useInsertionEffect
是一个新的钩子,它允许CSS-in-JS 库解决在渲染中注入样式的性能问题。除非您已经构建了 CSS-in-JS 库,否则我们不希望您使用它。这个钩子将在 DOM 发生变异之后运行,但在布局效果读取新布局之前。这解决了在 React 17 及更低版本中已经存在的问题,但在 React 18 中更为重要,因为 React 在并发渲染期间屈服于浏览器,使其有机会重新计算布局。
React DOM Client
react-dom/client
createRoot
render
: 为or创建根的新方法unmount
。使用它代替ReactDOM.render
. 没有它,React 18 中的新功能就无法工作。hydrateRoot
: 水合服务器渲染应用程序的新方法。使用它而不是ReactDOM.hydrate
与新的 React DOM 服务器 API 结合使用。没有它,React 18 中的新功能就无法工作。
两者都createRoot
接受hydrateRoot
一个新选项onRecoverableError
,以防你想在 React 从渲染期间的错误中恢复或日志记录时收到通知。默认情况下,React 将使用reportError
, 或console.error
在较旧的浏览器中。
React DOM Server
react-dom/server
完全支持流式传输 Suspense:
renderToPipeableStream
: 用于 Node 环境中的流式传输。renderToReadableStream
:适用于现代边缘运行时环境,例如 Deno 和 Cloudflare worker。
现有renderToString
方法继续有效,但不鼓励使用。
三、弃用了哪些呢
react-dom
react-dom
:ReactDOM.render
已弃用。使用它会警告并在 React 17 模式下运行您的应用程序。react-dom
:ReactDOM.hydrate
已弃用。使用它会警告并在 React 17 模式下运行您的应用程序。react-dom
:ReactDOM.unmountComponentAtNode
已弃用。react-dom
:ReactDOM.renderSubtreeIntoContainer
已弃用。react-dom/server
:ReactDOMServer.renderToNodeStream
已弃用。
四、升级
安装最新版
npm install react react-dom # or yarn add react react-dom
首次安装的话,在控制台中看到一个警告:
React 18 不再支持 ReactDOM.render。请改用 createRoot。在您切换到新的 API 之前,您的应用程序会像运行 React 17 一样运行。
React 18 引入了一个新的根 API,它为管理根提供了更好的人体工程学。新的根 API 还启用了新的并发渲染器,它允许您选择使用并发功能。
createRoot
import { createRoot } from 'react-dom/client'; const container = document.getElementById('app'); const root = createRoot(container); root.render(<App tab="home" />);
将unmountComponentAtNode改为root.unmount
root.unmount();
渲染中删除了回调
function AppWithCallbackAfterRender() { useEffect(() => { console.log('rendered'); }); return <App tab="home" /> } const container = document.getElementById('app'); const root = ReactDOM.createRoot(container); root.render(<AppWithCallbackAfterRender />);
服务器端渲染
import { hydrateRoot } from 'react-dom/client'; const container = document.getElementById('app'); const root = hydrateRoot(container, <App tab="home" />); // 与 createRoot 不同,您不需要在此处单独调用 root.render()
五、最后
在我们阅读完官方文档后,我们一定会进行更深层次的学习,比如看下框架底层是如何运行的,以及源码的阅读。
这里广东靓仔给下一些小建议:
- 在看源码前,我们先去官方文档复习下框架设计理念、源码分层设计
- 阅读下框架官方开发人员写的相关文章
- 借助框架的调用栈来进行源码的阅读,通过这个执行流程,我们就完整的对源码进行了一个初步的了解
- 接下来再对源码执行过程中涉及的所有函数逻辑梳理一遍