Skip to content

Conversation

@QDyanbing
Copy link

@QDyanbing QDyanbing commented Dec 17, 2025

fix: ant-design/ant-design#56230

Form.List 的更新(如 remove)内部会触发多次状态变更。在当前实现中,useWatch 会在这些内部步骤中被同步触发,导致一次操作出现多次更新,并可能读到尚未稳定的中间态数据。

Summary by CodeRabbit

发布说明

  • 文档

    • 更新了示例,展示基于动态列表的表单用法并加入初始值与增删控制
  • 测试

    • 采用可控假定定时器以提升测试稳定性并统一等待方式
    • 新增列表移除场景测试,确保无中间 undefined 值
    • 在测试环境中模拟 MessageChannel,提高宏任务相关测试可靠性
  • 变更

    • 精简并移除了部分内部批量更新相关公开接口和运行时接入点

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Dec 17, 2025

@QDyanbing is attempting to deploy a commit to the React Component Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Dec 17, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

移除 BatchUpdate 批量更新组件并引入 WatcherCenter 以集中批处理通知;重构 useForm/useWatch 通知路径与模块导入;测试改为使用假定时并新增用例验证 Form.List 删除时无中间 undefined 状态。

Changes

内聚组 / 文件(s) 变更摘要
表单监听系统重构
src/hooks/useForm.ts, src/hooks/useNotifyWatch.ts
移除 setBatchUpdate,新增 WatcherCenter,将原基于 namePath 的局部批处理替换为 watcherCenter.register()/notify(),通过宏任务(MessageChannel)去重并批量调度通知。
移除批量更新组件
src/BatchUpdate.tsx
删除文件及其导出类型 BatchTask、接口 BatchUpdateRef 和组件 BatchUpdate
表单核心逻辑调整
src/Form.tsx, src/FieldContext.ts, src/interface.ts
去除 BatchUpdate 相关导入与引用,从 FieldContext / InternalHooks / 接口中删除 setBatchUpdate 声明与使用。
模块导入路径重组
src/index.tsx, src/hooks/useWatch.ts
useForm/useWatch 的导入改为 ./hooks/... 并统一相对导入路径。
示例更新
docs/examples/debug.tsx
用基于 Antd V6 的 Form.List 示例替换静态示例,使用 Form.useWatch('names', form) 观察数组并渲染增删控件。
测试基础设施与用时工具变更
tests/setupAfterEnv.ts, tests/common/index.ts, tests/useWatch.test.tsx, tests/dependencies.test.tsx, tests/index.test.tsx, tests/validate.test.tsx
添加全局 window.MessageChannel Mock;引入并使用 waitFakeTime/jest 假定时代替原有 timeout;新增测试用例 "list remove should not trigger intermediate undefined value"。
工具/文档/依赖
src/utils/valueUtil.ts, package.json
更新 partialMatch 注释以声明默认值;将 devDependency rc-test 从 ^7.0.15 升级到 ^7.1.3。

Sequence Diagram(s)

sequenceDiagram
  participant Form as FormStore
  participant Watcher as WatcherCenter
  participant Scheduler as MessageChannel (macroTask)
  participant WatchCB as Watcher Callback

  Note over Form,Watcher: 字段值变化或更新触发
  Form->>Watcher: notify(namePath[])
  Watcher->>Watcher: 合并与去重 namePathList
  Watcher->>Scheduler: postMessage()(调度宏任务)
  Scheduler-->>Watcher: onmessage(执行宏任务)
  Watcher->>Form: getFieldsValue() / getFieldsValue(true)
  Watcher->>WatchCB: forEach(cb) cb(values, allValues, namePathList)
  Watcher->>Watcher: 清空 namePathList
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

需要重点检查:

  • src/hooks/useNotifyWatch.ts(WatcherCenter)的去重逻辑、taskId 与宏任务(MessageChannel)调度实现;
  • src/hooks/useForm.ts 中所有通知调用是否已正确迁移为 watcherCenter.notify,避免遗漏或重复通知;
  • 测试改动:tests/useWatch.test.tsx 新增用例与 tests/setupAfterEnv.ts 中 MessageChannel Mock 的行为是否与真实环境调度语义一致。

Possibly related PRs

Suggested reviewers

  • crazyair

Poem

🐰 我在草间跳着调度舞,
旧批量去,中心来做主,
列表删去不留影,值更明,
消息桥轻敲,通知整齐如束。

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了主要改动:修复useWatch在Form.List更新期间被触发两次的问题,直接对应PR目标和linked issue内容。
Linked Issues check ✅ Passed 代码改动完整实现了linked issue需求:移除BatchUpdate机制,引入WatcherCenter进行批处理通知,防止Form.List移除时产生中间undefined状态。
Out of Scope Changes check ✅ Passed 所有改动均与修复目标相关:移除旧的BatchUpdate实现、引入新的WatcherCenter机制、调整import路径、更新测试工具链。无不相关的改动。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fc1f633 and 832be04.

📒 Files selected for processing (1)
  • src/hooks/useForm.ts (7 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/hooks/useForm.ts (2)
src/hooks/useNotifyWatch.ts (1)
  • WatcherCenter (14-62)
src/interface.ts (1)
  • InternalNamePath (6-6)
🔇 Additional comments (7)
src/hooks/useForm.ts (7)

80-80: LGTM!

WatcherCenter 初始化正确,将 FormStore 实例传递给 WatcherCenter 以便集中管理 watch 通知。这种设计将通知批处理逻辑从 FormStore 中分离出来,提高了代码的模块化程度。


198-204: LGTM!

registerWatchnotifyWatch 正确委托给 WatcherCenter,实现了通知逻辑的集中管理。根据 WatcherCenter 的实现,通知会通过 macroTask 进行批处理,这应该能够解决 Form.List 更新时 useWatch 被同步调用两次的问题。


637-637: LGTM!

字段注册后正确调用 notifyWatch 通知观察者。将 namePath 包装为数组以匹配新的 API 签名。


677-677: LGTM!

字段注销时正确通知观察者,与注册时的通知保持对称性。


1046-1046: LGTM!

注释清晰地说明了 useRef 模式的意图,即在多次渲染中维护单例的 FormStore 实例。这是一个有益的文档改进。


5-5: 导入路径已正确调整。

所有导入路径均已验证,并正确反映目录结构变化:

  • FieldContext../FieldContext 导入正确
  • interface../interface 导入正确
  • 工具模块从 ../utils/* 导入正确
  • WatcherCenter./useNotifyWatch 导入正确

文件从项目根级重构到 src/hooks/ 子目录后,导入路径已正确更新。


549-549: 验证 Form.List 删除时的批处理通知机制是否按预期工作

所有通知调用点已正确更新至使用 notifyWatch API。根据更改模式,该机制应能防止在 Form.List 更新(如删除操作)期间同步触发多个中间状态的通知。

需要通过以下方式进行验证:

  • 检查是否存在针对 Form.List 删除操作的测试用例,确保 useWatch 仅触发一次且直接从最终状态过渡(而非经历 [1, undefined] 等中间状态)
  • 确认批处理机制已在所有相关操作点(resetFields、setFields、updateValue、setFieldsValue)中一致应用

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @QDyanbing, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a specific bug within the Form.List component where the useWatch hook would sometimes trigger multiple times or with an incorrect intermediate state, specifically including undefined values, when list items were modified or removed. The core change involves refactoring the internal notification mechanism within the FormStore to use a batched approach, ensuring useWatch subscribers receive updates only once with the final, correct form state. A new test case has been added to validate this fix, preventing regressions.

Highlights

  • Optimized useWatch Notifications: Replaced direct notifyWatch calls with batchNotifyWatch in the FormStore to prevent redundant triggers when form values are updated, particularly within Form.List components.
  • Resolved Intermediate Undefined Values: Fixed an issue where useWatch would incorrectly report intermediate undefined values when items were removed from a Form.List, ensuring only the final, correct state is propagated.
  • Enhanced Test Coverage: Added a new test case to specifically verify that Form.List item removal does not lead to useWatch triggering with undesirable intermediate undefined states, preventing regressions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

这个 PR 旨在修复 Form.List 更新(如 remove)时 useWatch 会被多次触发并可能读到不稳定中间态数据的问题。通过在 updateValue 方法中将 notifyWatch 的直接调用改为 batchNotifyWatch,利用 useLayoutEffect 将通知批量处理,确保 useWatch 只在所有同步状态更新完成后收到一次通知,从而获取到最终的稳定状态。这个改动是合理的,并且新增的测试用例也很好地覆盖了 Form.List remove 操作的场景,验证了中间状态不会被观察到。

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
tests/useWatch.test.tsx (1)

540-603: 建议使用 remove(index) 保持与现有测试的一致性。

测试逻辑正确,有效验证了修复效果。但是,Line 562 使用了硬编码的 remove(1),而现有的列表测试(Line 184)使用的是 remove(index)

建议应用以下修改以保持一致性:

-                        <a className="remove" onClick={() => remove(1)} />
+                        <a className="remove" onClick={() => remove(index)} />

这样做不会改变测试行为(因为测试只点击第一个 remove 按钮),但会使代码更符合既定模式,减少未来维护时的困惑。

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3247c62 and 982293e.

📒 Files selected for processing (2)
  • src/useForm.ts (1 hunks)
  • tests/useWatch.test.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
tests/useWatch.test.tsx (4)
docs/examples/useWatch-selector.tsx (1)
  • form (12-42)
docs/examples/useWatch.tsx (1)
  • form (38-123)
src/index.tsx (2)
  • List (34-34)
  • Field (34-34)
tests/common/InfoField.tsx (1)
  • Input (9-11)
🔇 Additional comments (2)
src/useForm.ts (2)

220-227: 实现正确:批量通知机制有效防止中间状态。

batchNotifyWatch 方法正确地将多个 namePath 更新累积到一起,并通过现有的批处理机制在单次回调中触发所有监听器。这确保了 useWatch 不会收到中间的 undefined 值。


778-778: 正确应用批量通知,修复了 Form.List 删除项时的中间状态问题。

notifyWatch([namePath]) 替换为 batchNotifyWatch(namePath) 确保了在快速连续更新期间(如 Form.List 删除操作),监听器只会在批处理完成后收到最终状态,而不会收到中间的 undefined 值。

@codecov
Copy link

codecov bot commented Dec 18, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.53%. Comparing base (3247c62) to head (982293e).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #772   +/-   ##
=======================================
  Coverage   99.53%   99.53%           
=======================================
  Files          19       19           
  Lines        1299     1299           
  Branches      319      303   -16     
=======================================
  Hits         1293     1293           
  Misses          6        6           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/Form.tsx (1)

1-189: 移除 src/interface.ts 中未使用的 BatchUpdate 导入。

在 src/interface.ts 中发现了对不存在的 BatchUpdate 模块的未使用导入:import type { BatchTask } from './BatchUpdate';。该导入应被完全移除,以完成 BatchUpdate 组件的彻底清理。

🧹 Nitpick comments (6)
docs/examples/debug.tsx (1)

47-47: 按钮缺少 type="button" 属性

这个按钮没有指定 type 属性,在 <form> 标签内默认会是 type="submit",可能导致意外的表单提交行为。

🔎 建议修复
-                    <button onClick={() => remove(1)}>删除索引 1</button>
+                    <button type="button" onClick={() => remove(1)}>删除索引 1</button>
src/hooks/useForm.ts (4)

202-222: 建议删除注释掉的代码

这些注释掉的代码是旧的批处理逻辑的残留,会影响代码可读性。建议在 PR 合并前删除这些注释。

🔎 建议修复
  private notifyWatch = (namePath: InternalNamePath[] = []) => {
-    // // No need to cost perf when nothing need to watch
-    // if (this.watchList.length) {
-    //   const values = this.getFieldsValue();
-    //   const allValues = this.getFieldsValue(true);
-
-    //   this.watchList.forEach(callback => {
-    //     callback(values, allValues, namePath);
-    //   });
-    // }
    this.watcherCenter.notify(namePath);
  };
-
-  // private notifyWatchNamePathList: InternalNamePath[] = [];
-  // private batchNotifyWatch = (namePath: InternalNamePath) => {
-  //   this.notifyWatchNamePathList.push(namePath);
-  //   this.batch('notifyWatch', () => {
-  //     this.notifyWatch(this.notifyWatchNamePathList);
-  //     this.notifyWatchNamePathList = [];
-  //   });
-  // };

655-656: 同样建议删除注释

此处也有类似的注释残留。

🔎 建议修复
-    // this.batchNotifyWatch(namePath);
     this.notifyWatch([namePath]);

696-697: 同样建议删除注释

🔎 建议修复
-      // this.batchNotifyWatch(namePath);
       this.notifyWatch([namePath]);

763-764: 同样建议删除注释

🔎 建议修复
-    // this.batchNotifyWatch(namePath);
     this.notifyWatch([namePath]);
src/hooks/useNotifyWatch.ts (1)

44-61: 批处理执行逻辑

taskId 递增和比较机制确保了只有最新的批次会执行回调,避免了过时数据的问题。执行完成后清空 namePathList 也是正确的做法。

一个小建议:可以考虑在 watcherList.size 为 0 时提前返回,避免不必要的 macroTask 调度。

🔎 可选优化:提前检查是否有监听器
  public notify(namePath: InternalNamePath[]) {
+   // Skip if no watchers registered
+   if (!this.watcherList.size) {
+     return;
+   }
+
    // Insert with deduplication
    namePath.forEach(path => {
      if (this.namePathList.every(exist => !matchNamePath(exist, path))) {
        this.namePathList.push(path);
      }
    });

    this.doBatch();
  }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 982293e and acf49c2.

📒 Files selected for processing (17)
  • docs/examples/debug.tsx (1 hunks)
  • package.json (1 hunks)
  • src/BatchUpdate.tsx (0 hunks)
  • src/FieldContext.ts (0 hunks)
  • src/Form.tsx (1 hunks)
  • src/hooks/useForm.ts (8 hunks)
  • src/hooks/useNotifyWatch.ts (1 hunks)
  • src/hooks/useWatch.ts (1 hunks)
  • src/index.tsx (1 hunks)
  • src/interface.ts (0 hunks)
  • src/utils/valueUtil.ts (1 hunks)
  • tests/common/index.ts (2 hunks)
  • tests/dependencies.test.tsx (4 hunks)
  • tests/index.test.tsx (5 hunks)
  • tests/setupAfterEnv.ts (1 hunks)
  • tests/useWatch.test.tsx (13 hunks)
  • tests/validate.test.tsx (2 hunks)
💤 Files with no reviewable changes (3)
  • src/interface.ts
  • src/FieldContext.ts
  • src/BatchUpdate.tsx
✅ Files skipped from review due to trivial changes (1)
  • package.json
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/useWatch.test.tsx
🧰 Additional context used
🧬 Code graph analysis (5)
tests/common/index.ts (1)
tests/common/timeout.ts (1)
  • timeout (3-7)
tests/validate.test.tsx (2)
tests/common/timeout.ts (1)
  • waitFakeTime (9-15)
tests/common/index.ts (3)
  • matchError (49-77)
  • changeValue (29-47)
  • getInput (5-25)
src/hooks/useForm.ts (2)
src/hooks/useNotifyWatch.ts (1)
  • WatcherCenter (14-62)
src/interface.ts (1)
  • InternalNamePath (6-6)
tests/dependencies.test.tsx (1)
tests/common/timeout.ts (1)
  • waitFakeTime (9-15)
tests/index.test.tsx (2)
tests/common/timeout.ts (1)
  • waitFakeTime (9-15)
tests/common/index.ts (1)
  • matchError (49-77)
🔇 Additional comments (14)
src/utils/valueUtil.ts (1)

51-51: LGTM!文档改进清晰。

参数说明更新准确地反映了 partialMatch 的默认值行为,与函数签名(第 56 行)中的 partialMatch = false 一致。

tests/setupAfterEnv.ts (1)

3-30: MessageChannel mock 实现正确。

该 mock 正确实现了端口间的消息传递机制。postMessage 使用 10ms 延迟来模拟异步行为,这与测试套件中新引入的 waitFakeTime 工具和假计时器模式保持一致。

src/index.tsx (2)

5-5: LGTM!导入路径更新正确。

useForm 的导入路径从 './useForm' 更新为 './hooks/useForm',与项目重组 hook 到 src/hooks/ 目录的架构一致。


11-11: LGTM!导入路径更新正确。

useWatch 的导入路径更新为 './hooks/useWatch',与项目的模块化重组保持一致。

tests/common/index.ts (2)

27-27: 计时器检测模式实现巧妙。

通过在模块作用域捕获原生 setTimeout,可以在测试中可靠地检测 Jest 是否已模拟计时器。这种模式使 changeValue 函数能够同时支持真实计时器和假计时器。


29-46: LGTM!条件计时器处理正确。

changeValue 函数正确检测模拟计时器并相应地使用 jest.advanceTimersByTime(1000) 或实际的 timeout()。这确保了测试在两种计时器模式下都能正常工作。

tests/validate.test.tsx (1)

290-318: LGTM!假计时器迁移正确。

"form context" 测试已正确迁移以使用假计时器:

  • 在测试开始时设置 jest.useFakeTimers()
  • waitFakeTime() 替换 timeout() 调用
  • 在测试结束时正确清理 jest.useRealTimers()

这确保了确定性的定时行为并与测试套件中更广泛的假计时器模式保持一致。

tests/dependencies.test.tsx (1)

102-155: LGTM!假计时器迁移正确。

"should work when field is dirty" 测试已正确更新:

  • 在测试开始时设置假计时器
  • waitFakeTime() 替换 timeout() 以获得确定性的异步行为
  • 在测试结束时清理假计时器

这与测试套件中更广泛的假计时器迁移保持一致,并确保验证流程的可预测时序。

src/hooks/useWatch.ts (1)

3-12: LGTM!导入路径更新正确。

所有导入路径已正确更新以反映文件从 src/ 移动到 src/hooks/ 目录:

  • FieldContext:'./FieldContext''../FieldContext'
  • interface:'./interface''../interface'
  • typeUtil:'./utils/typeUtil''../utils/typeUtil'
  • valueUtil:'./utils/valueUtil''../utils/valueUtil'

这些更改纯粹是路径调整,没有功能性更改。

src/Form.tsx (1)

11-11: LGTM!导入路径更新正确。

useForm 的导入路径从 './useForm' 更新为 './hooks/useForm',与项目重组 hooks 到 src/hooks/ 目录的架构一致。

tests/index.test.tsx (1)

313-353: 测试改进:使用假定时器处理宏任务批处理

这些更改正确地将提交测试适配为使用假定时器,以配合新的 WatcherCenter 宏任务批处理机制。jest.useFakeTimers()jest.useRealTimers() 的配对使用确保了定时器状态在测试后正确恢复。

src/hooks/useForm.ts (1)

78-84: WatcherCenter 集成实现正确

使用 WatcherCenter 替代之前的批处理逻辑是合理的架构改进。通过宏任务延迟通知,可以有效避免 Form.List 操作过程中产生的中间状态触发 useWatch 多次回调的问题。

src/hooks/useNotifyWatch.ts (2)

33-42: 路径去重逻辑正确

使用 matchNamePath 进行去重可以正确处理嵌套路径的情况,避免重复通知。doBatch 在每次 notify 调用时都会被触发,但通过 taskId 机制确保只有最后一次调度的回调会真正执行。


5-12: 使用 MessageChannel 实现宏任务批处理效果最优

setTimeout(cb, 0) 在嵌套超过5层后会产生至少 4ms 的延迟,这使得 setTimeout 不是队列宏任务的最可靠方式。相比之下,MessageChannel 规避了这个限制,总是比 setTimeout 更快执行且耗时更少。这个选择对解决 Form.List 操作中的中间状态问题至关重要。

关于浏览器兼容性:MessageChannel 在 IE 10 及以上版本中支持,仅需关注 IE9 及更早版本的兼容性处理。MessageChannel 在跨浏览器中的可用性自 2015 年 9 月起已广泛支持,现代浏览器的兼容性不成问题。

Comment on lines 108 to 110
export function executeMicroTasks() {
jest.advanceTimersByTime(1000);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# 查找测试中计时器推进的使用模式和持续时间
rg -n "advanceTimersByTime|waitFakeTime" tests/ -A 2 -B 2

Repository: react-component/field-form

Length of output: 11308


🏁 Script executed:

# 查找 executeMicroTasks 的调用位置
rg -n "executeMicroTasks" tests/ -B 3 -A 3

Repository: react-component/field-form

Length of output: 308


🏁 Script executed:

# 查看 executeMicroTasks 周围的完整上下文和其他辅助函数
cat -n tests/common/index.ts | head -120 | tail -30

Repository: react-component/field-form

Length of output: 984


🏁 Script executed:

# 搜索整个测试目录看 executeMicroTasks 是否被导入或调用
rg -n "executeMicroTasks" .

Repository: react-component/field-form

Length of output: 135


🏁 Script executed:

# 检查 tests/common/index.ts 的导出内容
cat -n tests/common/index.ts | grep "export"

Repository: react-component/field-form

Length of output: 427


🏁 Script executed:

# 查看完整的 tests/common/index.ts 文件,特别是包含 act 和计时器相关的代码
cat -n tests/common/index.ts | head -50

Repository: react-component/field-form

Length of output: 1695


补充 act() 包装以保持一致性。

executeMicroTasks() 函数缺少 act() 包装,与同一文件中 changeValue() 函数的做法(第 39 行)不一致。应改为:

export function executeMicroTasks() {
  act(() => {
    jest.advanceTimersByTime(1000);
  });
}

1000ms 的持续时间与现有测试模式一致(如 changeValue() 中的用法),适合处理 WatcherCenter 批处理和消息通道调度。但必须用 act() 包装来确保 React 的副作用和状态更新得到正确处理。

🤖 Prompt for AI Agents
In tests/common/index.ts around lines 108 to 110, the executeMicroTasks()
function should be changed to wrap the jest.advanceTimersByTime(1000) call in
React's act() to match changeValue() behavior; update the function so it calls
act(() => { jest.advanceTimersByTime(1000); }); keeping the 1000ms duration
unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useWatch v6和v5版本行为不一致

2 participants