
Refine 中的 React 18 升级指南新特性、API 迁移与工程实践【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refineReact 18 是 React 发展史上的一个分水岭版本它首次把并发渲染Concurrent Rendering这一全新概念带入主流 React 应用。本指南基于 Refine 开源仓库中的技术文档系统梳理 React 17 存在的问题、React 18 的核心变更createRoot、hydrateRoot、自动批处理、Transitions 等并结合仓库内真实示例源码帮助你安全地把项目升级到 React 18 并重构既有代码。读完本文你将掌握 React 18 升级的完整路径、新旧 API 的对应关系以及在以 Refine 为代表的 React 应用中落地的具体写法。React 18 是什么在讨论React 18 有哪些新东西之前先明确概念任何从 18.0.0 起、低于 19.0.0 的稳定版 React 库都被称为 React 18。React 18 的诞生把并发渲染引入了 React 应用。此前 React 一直负责 DOM 渲染并为开发者提供控制与追踪组件生命周期的工具借助一批新能力React 18 可以主动调整渲染过程来适配客户端设备——这正是并发模式下 React 应用性能优化的根基。升级到 React 18React 社区提供了多种安装方式你可以新建一个 React 项目也可以在现有项目中重装 React从 React 17 迁移到 React 18。方式一CDN 引入适合无需构建的页面在 HTML 的script标签中用 CDN URL 作为src直接加载 React 18!-- Load React. -- !-- Note: when deploying, replace development.js with production.min.js. -- script srchttps://unpkg.com/react18/umd/react.development.js crossorigin/script script srchttps://unpkg.com/react-dom18/umd/react-dom.development.js crossorigin/script !-- Load our React component. -- script srcapp.js/script注意开发阶段使用development.js便于看到完整的警告与错误信息部署上线时务必替换为production.min.js。方式二NPM / Yarn 安装适合单页应用与打包项目在项目根目录的终端执行以下命令即可自动检测并安装或升级到最新的 React 与 React DOM# NPM npm install react react-dom # Yarn yarn add react react-dom从仓库现状看升级并非终点本仓库根目录 package.json 中已经使用types/react: ^19.1.0与types/react-dom: ^19.1.0说明 React 19 的类型体系已被广泛采用React 18 只是这条升级路径上的重要一站——掌握 18 的迁移模式就为后续升级打好了基础。React 17 的问题React 社区发现 17 及更早版本存在若干亟待改进的问题——如果 React 17 表现完美就不会有 React 18 及更高版本了。根据 React 18.0.0 的 changelog以下问题在 React 18 中得到修复组件返回undefined时渲染报错当组件返回值为undefined时应用会直接崩溃并展示错误信息控制台也会出现对应的报错提示。对已卸载组件调用setState产生警告尝试更新已卸载组件的状态时React 会警告可能的内存泄漏。Strict Mode 下的 console 日志抑制社区反馈Strict Mode 中 console 日志被抑制会让开发者困惑——理应出现两次的日志只显示一次。内存消耗React 17 及更早版本存在内存泄漏问题尤其在已卸载组件上更为明显。React 18 改变了什么React 18 的重心全面转向应用并发。这一理念具体化为新特性自动批处理Automatic Batching、Transition、Suspense新 APIcreateRoot、hydrateRoot、renderToPipeableStream、renderToReadableStream新 HooksuseId、useTransition、useDeferredValue、useSyncExternalStore、useInsertionEffect行为变更Strict Mode 更新、废弃ReactDOM.render与renderToString。下面逐一深入这些变更。客户端渲染Client Rendering从ReactDOM.render到createRoot升级后若仍沿用 React 17 的ReactDOM.render()API控制台会持续出现弃用警告。React 17 的典型写法是导入组件后渲染进一个idapp的 div 中import ReactDOM from react-dom; import App from App; const app document.getElementById(app); ReactDOM.render(App /, app);React 18 中改用从react-dom/client导入的createRoot()APIimport { createRoot } from react-dom/client; import App from App; const app document.getElementById(app); // create a root const root createRoot(app); //render app to root root.render(App /);这一迁移模式在 Refine 仓库的示例中被广泛采用。以 examples/base-antd/src/index.tsx 为例整个 Refine 应用的入口正是标准的createRoot写法import React from react; import { createRoot } from react-dom/client; import App from ./App; const container document.getElementById(root); // eslint-disable-next-line const root createRoot(container!); root.render( React.StrictMode App / /React.StrictMode, );可以推断仓库中 examples 目录下的绝大多数示例入口如auth-antd、base-chakra-ui、template-material-ui、pixels等都统一采用了createRoot StrictMode 的启动模式这本身就是 React 18 迁移后的标准答案先createRoot(container)创建根再通过root.render()挂载组件树StrictMode 在开发期帮助提前暴露不纯渲染等隐患。水合Hydration从ReactDOM.hydrate到hydrateRoot服务端渲染场景下React 17 使用ReactDOM.hydrate()API 进行带水合的渲染import * as ReactDOM from react-dom; import App from App; const app document.getElementById(app); // Render with hydration. ReactDOM.hydrate(App tabhome /, app);React 18 中水合改用从react-dom/client导入的hydrateRoot()API并且不再需要单独的render()方法import { hydrateRoot } from react-dom/client; import App from App; const app document.getElementById(app); const root hydrateRoot(app, App tabhome /);如果你同时关注流式渲染React 18 还提供了renderToPipeableStreamNode 环境与renderToReadableStreamWeb/Edge 环境两个新的服务端渲染 API用于取代renderToString。渲染回调Render Callback的移除与替代在 React 17 的render方法中可以把回调函数作为第三个参数传入使其在组件渲染或更新后执行import * as ReactDOM from react-dom; import App from App; const app document.getElementById(app); ReactDOM.render(app, App tabhome /, function() { // Called after initial render or any update. console.log(Rendered or Updated). });React 18 的createRoot不再支持回调参数因为回调会影响应用在渐进式/部分水合下的运行时行为。官方推荐的替代方案是在根元素上使用 ref 回调、setTimeout或requestIdleCallbackimport { createRoot } from react-dom/client; function App({ callback }) { // Callback will be called when the div is first created. return ( div ref{callback} h1Hello World/h1 /div ); } const app document.getElementById(root); const root createRoot(app); root.render(App callback{() console.log(Rendered or Updated)} /);这里 ref 回调在 div 首次创建时触发既保证了渲染完成后执行又不破坏并发渲染的调度语义。自动批处理Automatic Batching在 React 17 及更早版本中只有 React 事件处理器内的状态更新会被批处理。以handleClick为例所有状态在事件回调函数结束时一次性变更React 只重渲染一次const handleClick () { setFirstState(1); setSecondState(2); }但状态更新一旦发生在 Promise、原生事件或 React 事件处理器之外情况就不同了——每次setState都会触发一次重渲染fetch(https://api.com).then(() { setFirstState(1); setSecondState(2); }) //OR setTimeout(() { setFirstState(1); setSecondState(2); })React 18 的createRoot()使无论状态更新发生在应用何处都会被自动批处理React 在所有状态更新完成后统一重渲染页面。由于这是一项破坏性变更如果你确实需要强制同步刷新可以使用flushSync()API 关闭某段代码的自动批处理import { flushSync } from react-dom; function handleClick() { flushSync(() { setFirstState(1); }); flushSync(() { setSecondState(2); }); }上面的代码中每次调用flushSync()都会立即更新状态并让 React 重渲染一次——代价是失去批处理带来的性能收益因此应谨慎、局部地使用。过渡Transitions区分紧急与非紧急更新Transitions 让你把需要紧急/立即响应的状态更新和可以延后的状态更新区分开来。搜索框是经典场景用户输入时你要立即给出视觉反馈但真正触发搜索可以等用户输完再开始import { startTransition } from react; // Urgent: Show what was currently typed setSearchCurrentValue(input); startTransition(() { // Not-urgent: Show what was finally typed setSearchFinalValue(input); });这里用startTransition()代替setTimeout()来监控状态更新setSearchCurrentValue()只更新与即时反馈相关的状态setSearchFinalValue()更新最终用于触发搜索的状态。与setTimeout相比startTransition的更新可以被中断、可以追踪 pending 状态并且立即执行——这正是并发渲染调度能力的体现。与之配套的还有useTransitionHook可获取 pending 标志与useDeferredValueHook延迟派生值。放弃对 Internet Explorer 的支持React 社区同时放弃了 Internet Explorer。这意味着只有 React 17 及之前支持的浏览器特性能在 IE 上运行Promise、Object.assign、Symbol等现代浏览器特性将不再为 IE 提供 polyfill。React 18 相对 React 17 的优势了解了上述差异后你或许还在犹豫是否要切换到 React 18。一个没有带来更多价值的新版本是不值得被采纳的。并发是首要优势并发渲染不是某个单一功能而是一个全新概念它让运行在 React 18 及更高版本上的应用能够针对客户端设备优化性能——配合useTransition、useDeferredValue、Suspense 等 API可以精细控制渲染优先级避免大计算量更新阻塞用户交互。更优的内存管理React 18 通过在卸载时清理后台任务降低内存泄漏风险直接回应了 React 17 时代未卸载组件内存泄漏的痛点。在 Refine 项目中的落地实践把视角放回本仓库React 18 的迁移并不只是换个入口文件这么简单它还体现在项目工程化的方方面面入口统一为createRoot以 examples/base-antd/src/index.tsx 为代表的示例入口均采用createRoot(container!)root.render(React.StrictModeApp //React.StrictMode)的写法这是 React 18 客户端渲染的推荐形态升级时可直接对照改写。类型与依赖同步升级根目录 package.json 中的types/react、types/react-dom已指向^19.1.0说明类型定义需要与运行时版本匹配推进从 React 17 迁移到 18 时也应同步把types/react升级到 18.x 或更高。依赖版本由 pnpm 工作区统一管理本仓库通过 pnpm-workspace.yaml 与 lerna.json 组织多包结构升级 React 这类核心依赖时应先确认各子包refinedev/core、refinedev/antd、refinedev/mui等与目标 React 版本的兼容性再统一执行安装命令。结论读完本篇指南你应该已经清楚React 18 是一次从渲染机制到开发心智的全面升级。从ReactDOM.render迁移到createRoot、从ReactDOM.hydrate迁移到hydrateRoot用 ref 回调替代渲染回调理解自动批处理并用flushSync精准控制同步刷新再用startTransition/useTransition编排紧急与非紧急更新——这套组合拳足以让你平滑完成 React 17 → 18 的迁移并把并发能力真正用在自己的应用里。最后建议持续关注 React 库的 changelog及时跟进新版本与变更说明保持与 React 社区的同步——版本升级永远是一件常做常新的工程任务。【免费下载链接】refineA React Framework for building internal tools, admin panels, dashboards B2B apps with unmatched flexibility.项目地址: https://gitcode.com/GitHub_Trending/re/refine创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考