ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

awesome-copilot 中的 React 18 迁移指挥家:React 16/17 类组件代码库到 18.3.1 的编排式升级实战

awesome-copilot 中的 React 18 迁移指挥家:React 16/17 类组件代码库到 18.3.1 的编排式升级实战 awesome-copilot 中的 React 18 迁移指挥家React 16/17 类组件代码库到 18.3.1 的编排式升级实战【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot本篇文章以 awesome-copilot 仓库中 react18-commander.agent.md 这份 Agent 规格说明为骨架系统讲解如何用“编排式多 Agent 流水线”把 React 16/17 的类组件重代码库安全迁移到 React 18.3.1。你将掌握为什么精确锁定 18.3.1 而非最新 18.x、五阶段门禁流水线如何运作、基于 memory 的可断点续跑协议、三大不安全生命周期方法与自动批处理automatic batching的深层修复原理以及最终验收如何把控制台告警清零为后续 React 19 迁移铺平道路。仓库配套的五个子 Agent 规格react18-auditor、react18-dep-surgeon、react18-class-surgeon、react18-batching-fixer、react18-test-guardian与 react18-upgrade 插件 都围绕同一流水线设计可作为实战中的深度参考。迁移指挥官一份工作流编排规格而不是普通提示词react18-commander是 awesome-copilot 仓库中以“主控编排”为定位的 Agent 规格前端数据见 agents/react18-commander.agent.md 的 YAML front-matter它声明自己是React 16/17 → 18.3.1 迁移的主编排者Master orchestrator专为类组件为主class-component-heavy的代码库设计并明确列出了自身工具集与可调用的子 Agent 清单toolsagent、vscode/memory、edit/editFiles、execute/getTerminalOutput、execute/runInTerminal、read/terminalLastCommand、read/terminalSelection、search、search/usages、read/problems——即它既能调度子 Agent又能直接读终端、做全文搜索、改文件最终验收由它亲自跑。agentsreact18-auditor、react18-dep-surgeon、react18-class-surgeon、react18-batching-fixer、react18-test-guardian——五个专用子 Agent 分别覆盖审计、依赖、类组件手术、批处理修复、测试守卫。argument-hintJust activate to start the React 18 migration.——用户只需一句触发语即可启动整个流水线。从这一编排结构看这份文档的实质是一份“可执行的迁移作战计划”它不是罗列迁移知识点而是把一次大型重构拆成五个顺序执行、逐门门禁放行的阶段由统一的主控负责状态记账与断点续跑。插件侧 plugins/react18-upgrade/README.md 印证了这一家族化设计该插件打包了 6 个 Agent 与 7 个专项 skillreact-audit-grep-patterns、react18-batching-patterns、react18-dep-compatibility、react18-enzyme-to-rtl、react18-legacy-context、react18-lifecycle-patterns、react18-string-refs等可用copilot plugin install react18-upgradeawesome-copilot安装后整组使用。为什么偏偏是 18.3.1整份规格反复强调一个战略定位18.3.1 是 React 19 迁移的前置哨兵版本。理由非常具体React 18.3.1 被发布出来的目的就是对每个 React 19 将要移除的 API 显式地发出告警。一段在 18.3.1 下零告警跑通的代码就是可直接交给 React 19 迁移管弦乐队的代码库。因此这里采用的是精确锁版exact pinreact18.3.1react-dom18.3.1而不是^18或latest。把“升到 18 最新”改成“升到 18.3.1 这个具名检查点”本质上是把一个混沌的升级动作变成一个可验证、可交接的里程碑任何仍然存在的废弃 API 调用都会在构建/运行期以警告形式显形而警告就是 React 19 的“地雷清单”。记忆协议与启动序列让迁移可以被中断、被恢复Memory 状态机大型迁移几乎必然跨越多个会话。Commander 用仓库级 memory 记录迁移状态每次启动先读、每个门禁通过后写#tool:memory read repository react18-migration-state #tool:memory write repository react18-migration-state [state JSON]标准状态结构如下这是门禁放行的唯一事实来源{ phase: audit|deps|class-surgery|batching|tests|done, reactVersion: null, auditComplete: false, depsComplete: false, classSurgeryComplete: false, batchingComplete: false, testsComplete: false, consoleWarnings: 0, testFailures: 0, lastRun: ISO timestamp }phase字段的六种取值恰好一一对应五阶段流水线加一个done终态五个布尔标记分别对应每个阶段的“门禁已通过”。会话中途断掉后下一次激活只要读 memory 就能从第一个未完成阶段继续不重复执行已完成阶段。同样的记忆策略贯穿所有子 Agentauditor 写react18-audit-progress、dep-surgeon 写react18-deps-state、class-surgeon 按每个文件写react18-class-surgery-progress检查点、batching-fixer 写react18-batching-progress、test-guardian 写react18-test-state。子 Agent 级的细粒度记忆是主控级记忆的支撑——例如 class-surgeon 每改完一个文件就记录completed:[filename]:[patterns-fixed]即使中途断线也不必重新扫一遍已完成文件。Boot Sequence先诊断再进场Commander 每次启动按固定顺序执行读 memory向用户汇报哪些阶段已完成探测当前 React 版本node -e console.log(require(./node_modules/react/package.json).version) 2/dev/null || grep react package.json | head -3已在 18.3.x→ 跳过依赖阶段直接从 class-surgery 开始仍在 16.x/17.x→ 从 audit 阶段开始。这套启动逻辑保证了迁移“只做未做之事”版本探测决定起点memory 决定续跑位置两者组合即可在任何时刻安全恢复。五阶段门禁流水线Audit → Deps → Class Surgery → Batching → Tests每个阶段由 Commander 用#tool:agent唤醒对应子 Agent传给它完整上下文子 Agent 完成工作后返回结构化结论只有门禁条件Gate满足才允许推进到下一阶段并写 memory。整条链路上任何一环不合格都不会带病进入下一步。PHASE 1 - Audit读遍一切先不改任何代码Commander 把任务下发给react18-auditor“Deep-scan specialist”要求它全面扫描 React 18 迁移问题点聚焦不安全生命周期方法、遗留 Context、字符串 ref、findDOMNode、ReactDOM.render、事件委托假设、自动批处理漏洞以及一切会被 18.3.1 警告的模式并把完整报告写入.github/react18-audit.md按类别返回问题计数。auditor 的规格把“读代码”拆成可复现的 grep 战役详见 agents/react18-auditor.agent.md值得直接抄进你自己的审计流程PHASE 0 代码库画像统计源码文件总数、类组件数、函数组件数、当前 React 版本用“类组件 / 函数组件比例”预估工作量PHASE 1 不安全生命周期分别 grepcomponentWillMount、componentWillReceiveProps、componentWillUpdate排除UNSAFE_前缀与测试文件同时查UNSAFE_component判断是否已做过部分迁移PHASE 2 批处理漏洞找出async类方法中的多处setState、setTimeout/Promise回调里的setState、原生事件处理器里的setState——并特别标注“await 之后读取 this.state”的危险模式PHASE 3 遗留 ContextchildContextTypes、contextTypes、getChildContext、this.contextPHASE 4 字符串 refref...与this.refs.PHASE 5 findDOMNodefindDOMNode/ReactDOM.findDOMNodePHASE 6 Root APIReactDOM.render、ReactDOM.hydrate、unmountComponentAtNodePHASE 7 事件委托document.addEventListener/removeEventListener特别是监听 click、keydown、focus、blur 且与 React 合成事件重叠者PHASE 8 StrictMode 状态是否启用过StrictMode——没用过则告警从未暴露命中数会很大PHASE 9 依赖兼容性用npm ls抓 peer 冲突并核对各库对 React 18 的最低要求PHASE 10 测试文件审计遗留 render、手动假定时钟、react-dom/test-utils导入、Enzyme 使用情况。auditor 的产出报告模板是一个分级清单 静默运行时破坏者批处理漏洞、Enzyme、 不安全生命周期、 遗留 Root API 与废弃 API、 事件委托审计、 依赖问题最后是 15 步的“Ordered Migration Plan”、需改动文件清单与各类别总计。仓库中相应 skill如skills/react-audit-grep-patterns目录下的参考文档把其中部分 grep 模式沉淀成了可复用资产。Gate阶段门槛.github/react18-audit.md存在且类别填充完整。Memory 写入{phase:deps,auditComplete:true}。PHASE 2 - Dependency Surgery精确锁版并拦截 Enzyme依赖阶段由react18-dep-surgeon执行其硬性要求是精确锁版详见 agents/react18-dep-surgeon.agent.md# 精确锁版——不是 ^18不是 latest npm install --save-exact react18.3.1 react-dom18.3.1 # 验证 node -e const rrequire(react); console.log(React:, r.version) node -e const rrequire(react-dom); console.log(ReactDOM:, r.version)阶段前的硬阻断检查是 EnzymeEnzyme 没有 React 18 适配器。一旦在package.json或依赖树里发现enzymedep-surgeon不得继续升级 React而是回报BLOCKED - Enzyme detected. react18-test-guardian must rewrite all Enzyme tests to RTL first——因为在 Enzyme 存在时安装 React 18会让全部 Enzyme 测试以无解的方式失败。配套依赖升级基线仓库规格明确列出的版本要求依赖要求原因react/react-dom精确18.3.1具名检查点显式暴露 React 19 将移除的 APItesting-library/react^14.0.0RTL ≤13 内部仍用ReactDOM.render在 18 并发模式下损坏v14 改用createRoottesting-library/jest-dom^6.0.0配套更新testing-library/user-event^14.0.0v14 起userEvent变为 async APIapollo/client3.83.8 起按并发模式要求使用useSyncExternalStoreemotion/react11.10支持 React 18react-router-domv6v5 与 React 18 peer 依赖冲突且 v6 是破坏性 API 变更react-redux8v8 经useSyncExternalStore支持并发模式v5 路由器属于需要单独决策的升级v5 → v6 是整体 API 重构hooks、嵌套路由全变规格的处理方式是停住并上报 Commander——由指挥官决定是单独排一期路由器迁移还是先用带 React 18 peer 变通方案的react-router-dom^5.3.4配合--legacy-peer-deps但必须留档说明原因。冲突解决纪律很明确绝不用--force--legacy-peer-deps仅在“该包尚未发布 React 18 兼容版本”时允许且必须记录原因。阶段收尾做干净重装 校验rm -rf node_modules package-lock.json npm install npm ls 21 | grep -E WARN|ERR|peer | wc -l # 期望 0子 Agent 最终向 Commander 返回GO / NO-GOGO 需同时满足react18.3.1精确、react-dom18.3.1精确、testing-library/react14.x、npm ls零 peer 错误、无 EnzymeNO-GO 的典型触发条件包括 Enzyme 仍存在硬阻断、版本不等于 18.3.1、peer 错误未清。GateGO react18.3.1确认 0 peer 错误。Memory 写入{phase:class-surgery,depsComplete:true,reactVersion:18.3.1}。PHASE 3 - Class Component Surgery语义迁移而不是贴 UNSAFE_ 膏药类组件手术是整个流水线的重头执行者是react18-class-surgeon其任务清单覆盖八类模式。关键方法论在规格中被反复强调不要只加UNSAFE_前缀敷衍——那只是消音不是修复React 19 还得再返工。要做真正的语义迁移。三大不安全生命周期方法选择正确的落点Commander 交给 class-surgeon 的迁移映射是componentWillMount→componentDidMount副作用或constructor初始化 state/依据 props 推导初始 statecomponentWillReceiveProps→纯推导用getDerivedStateFromProps有副作用/异步用componentDidUpdatecomponentWillUpdate→ 需要先读 DOM 用getSnapshotBeforeUpdate配componentDidUpdate(prevProps, prevState, snapshot)消费快照纯副作用则挪进componentDidUpdate。例如依据 props 变化触发异步拉取的经典迁移规格原文模式// BeforecomponentWillReceiveProps componentWillReceiveProps(nextProps) { if (nextProps.userId ! this.props.userId) { this.setState({ userData: null, loading: true }); fetchUser(nextProps.userId).then(data this.setState({ userData: data, loading: false })); } } // AftercomponentDidUpdate副作用必须放这里 componentDidUpdate(prevProps) { if (prevProps.userId ! this.props.userId) { this.setState({ userData: null, loading: true }); fetchUser(this.props.userId).then(data this.setState({ userData: data, loading: false })); } }注意语义细节componentWillReceiveProps(nextProps)比较的是“即将到来的新 props 与当前 props”而componentDidUpdate只能拿到prevProps因此比较方向要翻转。而纯状态派生则要求走static getDerivedStateFromProps——但规格特别警示它在每次 render 都会触发不只 props 变化时必须把前值存进 state 做 diff否则会陷入无限派生循环static getDerivedStateFromProps(props, state) { if (props.items ! state.prevItems) { return { sortedItems: sortItems(props.items), prevItems: props.items, }; } return null; } // 同时在 constructor 里初始化 this.state { ..., prevItems: props.items }其余五类 API 迁移遗留 ContextcontextTypes/childContextTypes/getChildContext→createContext这是跨文件迁移——必须先找到 provider 及其所有 consumer。Provider 侧把getChildContext()返回的对象变成ThemeContext value{...}类 consumer 侧用单数static contextType ThemeContext替换复数contextTypes。字符串 refrefmyInputthis.refs.myInput→React.createRef()constructor 中创建this.myInputRef React.createRef()JSX 写作ref{this.myInputRef}访问改为this.myInputRef.current。findDOMNode→ 直接 ref不再ReactDOM.findDOMNode(this)拿 DOM 节点而是把ref挂到组件根元素上直接持有节点引用。ReactDOM.render→createRoot迁移入口文件src/index.js/main.js这是开启自动批处理与 React 18 特性的前提——停留在遗留 root 上的应用拿不到批处理修复// Before import ReactDOM from react-dom; ReactDOM.render(App /, document.getElementById(root)); // After import { createRoot } from react-dom/client; const root createRoot(document.getElementById(root)); root.render(App /);ReactDOM.hydrate→hydrateRootSSR 场景同理。class-surgeon 的执行纪律见 agents/react18-class-surgeon.agent.md 的 Execution Rules一次只处理一个文件、每文件全量迁移完再进下一个、每文件写 memory 检查点、绝不触碰测试文件、保留全部业务逻辑/注释/Emotion 样式/Apollo hooks。阶段完成用四组 grep 自检清零不安全生命周期0、遗留 context0、this.refs0、ReactDOM.render0。Gate源码中废弃模式清零 构建成功。Memory 写入{phase:batching,classSurgeryComplete:true}。PHASE 4 - Automatic Batching Surgery处理“最阴险的静默运行时破坏者”批处理阶段交给react18-batching-fixer。之所以是“最阴险的破坏”因为没有警告、没有报错只是状态行为变了。规格用并排对照把新旧世界差异讲得极清楚// React 17旧世界——async/setTimeout 中的 setState 立即重渲染 this.setState({ loading: true }); // → 立即 re-renderthis.state.loading true const data await fetchData(); if (this.state.loading) { // ← 读到的已是更新后的值 this.setState({ data, loading: false }); } // React 18新世界——Promise/setTimeout/原生事件里也自动批处理 this.setState({ loading: true }); // → BATCHED没有立即 re-render const data await fetchData(); if (this.state.loading) { // ← 仍是 false条件静默失败后续 setState 永不执行 this.setState({ data, loading: false }); // ← never called } // 所有 setState 在最后一次性 flush类组件中“异步取数 → setState → 条件 setState”这类状态链在 18 下必然出错。修复决策被规格提炼为一张分诊表这是本阶段最值得记住的判断准则场景手段await 之后读this.state只为做决策重构用函数式 setState 或去掉中间条件不要 flushSync中间 UI 状态必须对用户可见加载 spinner 先于请求出现、向导/进度分步flushSync强制同步渲染.then()/.catch()中顺序敏感的 setState优先重构为 async/try-catch确需中间渲染才 flushSyncflushSync的用法从react-dom导入不是react-dom/clientimport { flushSync } from react-dom; async processOrder() { flushSync(() this.setState({ status: loading })); // 强制先渲染一步 await validateOrder(); flushSync(() this.setState({ status: processing })); // 再渲染一步 await processPayment(); this.setState({ status: done }); // 最后一步无需 flushSync }默认偏好是先重构、慎用 flushSync——只有 UI 行为在语义上依赖中间渲染时才动用后者。阶段尾声向.github/react18-audit.md追加“Automatic Batching Fix Status”段审查方法数、flushSync 插入数、纯重构数、转交 test-guardian 的测试模式数。GateAgent 确认批处理审计完成无运行时状态顺序 bug。Memory 写入{phase:tests,batchingComplete:true}。PHASE 5 - Test Suite Fix Verification跑到零失败为止测试阶段由react18-test-guardian兜底。由于批处理行为改变和 RTL v14 的 API 变化旧测试大面积失败是常态规格明确“不跑到零失败不罢休”。测试失败可按类型分诊详见 agents/react18-test-guardian.agent.md 的 Triage Table错误表现根因修复Enzyme cannot find module react-dom/adapter无 React 18 适配器整段重写为 RTLact() not returned异步状态更新逃出 actawait act(async () {...})或waitForLoading...立即断言找不到自动批处理推迟了渲染await waitFor(...)userEvent.click is not a functionRTL v14 API 变化userEvent.setup()await user.click()调用次数断言Expected 2, received 1StrictMode 双调用变化跑一次取真实次数再更新断言MockedProvider 解构 undefinedApollo React 18 时序断言外包waitFor其中三条 React 18 测试语义值得展开异步 actReact 18 对异步更新的 act 更严格同步act(() { fireEvent.click(...) })之后立即断言中间态会失败需改await act(async () {...})或直接用 RTL 内置异步工具waitFor/findBy*它们内部已包 act。批处理回归测试任何“fireEvent 后紧跟基于状态的同步 expect无 waitFor”都是候选问题中间态断言必须改await waitFor(...)。StrictMode 双调用React 18 开发模式会双调用 render、useState/useReducer 初始化、useEffect cleanupsetup、类构造函数与 render测试若断言“被调用 N 次”会翻车——规格的策略是不要猜跑一遍取真实次数再更新。另一个常见修复是userEvent.setup()await user.click()的 v14 异步写法。若项目存在自定义 render helper如renderWithProviders、customRender需确认其底层是 RTL v14 的render内部已走createRoot并示范了用MockedProvider mocks{mocks}包 wrapper 的 React 18 兼容写法。执行循环上先跑全量拿失败清单、按类别分组、逐文件修复并单文件重跑直至全绿。Gatenpm test→ 0 failures、0 errors。Memory 写入{phase:done,testsComplete:true,testFailures:0}。最终验收门禁Commander 亲自执行第五阶段结束后Commander 不再假手他人直接在终端跑验收脚本echo BUILD npm run build 21 | tail -20 echo TESTS npm test -- --watchAllfalse --passWithNoTests --forceExit 21 | grep -E Tests:|Test Suites:|FAIL echo REACT 18.3.1 DEPRECATION WARNINGS npm run build 21 | grep -i warning\|deprecated\|UNSAFE_ | head -20只有在以下三个条件同时满足时才允许宣告 COMPLETE ✅构建退出码为 0、测试 0 失败、构建输出中无任何 React 弃用警告。若告警仍残留——按规格的比喻那些是React 19 的地雷——必须带着具体警告文本重新唤醒react18-class-surgeon再次处理直到清零。为什么 16/17 → 18 比 18 → 19 更难规格单列一节解释这一反直觉结论四类“沉默工作了很多年”的模式正是难点所在自动批处理是头号静默运行时破坏者16/17 中 Promise、setTimeout 里的 setState 会立即触发重渲染18 起统一批处理。类组件中“异步取数 → setState → 条件 setState”的链式逻辑必然出错且无警告无声失败。遗留生命周期方法在非 StrictMode 下从不报错componentWillMount等虽在 16.3 已被废弃但只要应用没开 StrictMode16/17 会继续静默调用一个从未用过 StrictMode 的代码库可能囤积成百上千处此类调用。事件委托在 React 17 已改挂载点事件从document移到根容器。若团队从 16 一路小版本补丁到 18 而从未真正做过 17 迁移残留的document.addEventListener模式可能再也收不到事件。遗留 Context 在 16/17 全程静默可用主题、鉴权常靠它实现直到 React 19 才真正移除。所以规格反复说“18.3.1 的显式警告是你的朋友”——它把这些历史欠账一次性照出来。本次迁移的目标产物是一个18.3.1 下零警告的基线代码库好让后续 React 19 编排仓库中对应的 react19-commander.agent.md 家族同样存在能干干净净地开场。落地清单一份可直接照做的迁移检查表Commander 规格末尾给出了完整 checklist综合全篇可归结为以下可执行顺序对应仓库 agents/react18-commander.agent.md 原文清单生成审计报告.github/react18-audit.md精确安装react18.3.1react-dom18.3.1升级testing-library/react14解决全部 peer 依赖npm ls零错误拦截 EnzymecomponentWillMount→componentDidMount/ constructorcomponentWillReceiveProps→getDerivedStateFromProps/componentDidUpdatecomponentWillUpdate→getSnapshotBeforeUpdate/componentDidUpdate遗留 Context →createContext含全部 consumer字符串 ref →React.createRef()移除findDOMNode→ 直接 refReactDOM.render→createRootReactDOM.hydrate→hydrateRoot定位并修复自动批处理回归必要时插入flushSync复核事件委托假设document.addEventListener全部测试通过0 失败构建成功React 18.3.1 弃用警告清零阅读延伸与使用方式主控规格agents/react18-commander.agent.md —— 五阶段流水线、门禁与验收标准的总纲。五个执行子 Agentreact18-auditor扫描与报告、react18-dep-surgeon锁版与阻断、react18-class-surgeon生命周期/API 迁移样板代码、react18-batching-fixer批处理分诊、react18-test-guardianRTL v14/StrictMode/Enzyme 测试修复。整组插件形态plugins/react18-upgrade/README.md —— 6 Agent 7 Skill 的一键安装与快速开始说明安装命令为copilot plugin install react18-upgradeawesome-copilot随后只需对 Copilot 说 “Start implementing React 18 migration for my class-component codebase” 即可唤起整套流水线。配套 skillskills/react18-lifecycle-patterns、skills/react18-batching-patterns、skills/react18-legacy-context、skills/react18-string-refs、skills/react18-enzyme-to-rtl、skills/react18-dep-compatibility、skills/react-audit-grep-patterns目录下的文档分别为各阶段提供更细的迁移模式与参考实现。本文所述全部版本要求、迁移映射与修复决策均取自上述仓库文件实际执行时请以你项目package.json的依赖现状为准并优先在可回滚的分支上按阶段推进。当你的代码库在 18.3.1 下达成“零告警、零失败”时就等于拿到了通往 React 19 的干净入场券。【免费下载链接】awesome-copilotCommunity-contributed instructions, agents, skills, and configurations to help you make the most of GitHub Copilot.项目地址: https://gitcode.com/GitHub_Trending/aw/awesome-copilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表