Skip to content

Conversation

@crazyair
Copy link
Contributor

@crazyair crazyair commented Sep 3, 2025

Summary by CodeRabbit

发布说明

  • 新功能

    • 新增文档和代码示例,演示动态列表中字段的卸载和隐藏功能。
  • 改进

    • 优化表单列表中字段值的处理逻辑,提升动态挂载/卸载字段的稳定性。
    • 完善表单验证流程以支持复杂列表结构。
  • 测试

    • 扩展测试覆盖,验证列表字段的卸载行为和验证器功能。

@coderabbitai
Copy link

coderabbitai bot commented Sep 3, 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

此PR为表单列表引入动态字段卸载/挂载支持。核心变更包括重构字段实体处理逻辑、添加灵活字段类型、新增示例和测试,以及实现字段值提取的精细控制机制。

Changes

Cohort / File(s) Summary
文档与示例
docs/demo/list-unmount.md, docs/examples/list-unmount.tsx
新增列表字段动态卸载示例文档与React演示组件,展示Form.List中条件渲染字段的行为
表单核心逻辑重构
src/useForm.ts
重命名InvalidateFieldEntity为FlexibleFieldEntity;引入finalValueNamePathList追踪最终值提取路径;调整getFieldsValue、getFieldsError、validateFields等方法的名路径处理逻辑;合并onValuesChange回调前通过getFieldsValue获取最新聚合状态
类型与工具更新
src/interface.ts, src/utils/valueUtil.ts
FieldEntity添加INVALIDATE_NAME_PATH字段;GetFieldsValueConfig弃用strict选项;新增cloneByNamePathList工具函数用于按名路径列表克隆存储值
测试扩展
tests/list.test.tsx
重命名现有测试;新增"list unmount"测试验证列表项可见性切换行为;新增"list rules"测试验证列表级验证器触发流程

Sequence Diagram

sequenceDiagram
    participant User
    participant Form as Form Component
    participant useForm
    participant Validator as Field Validator
    participant Store as Field Store

    rect rgb(240, 248, 255)
    Note over User,Store: 初始提交流程
    User->>Form: 点击提交
    Form->>useForm: validateFields()
    useForm->>useForm: 构建finalValueNamePathList
    useForm->>Store: getFieldsValue(finalValueNamePathList)
    Store-->>useForm: 返回表单值(含所有字段)
    useForm->>Validator: 触发验证
    Validator-->>useForm: 验证通过
    useForm->>Form: onFinish(values)
    end

    rect rgb(240, 255, 240)
    Note over User,Store: 切换可见性阶段
    User->>Form: 点击隐藏/显示按钮
    Form->>Form: 重新渲染,age字段卸载
    useForm->>Store: 标记age字段为INVALIDATE_NAME_PATH
    end

    rect rgb(255, 248, 240)
    Note over User,Store: 再次提交流程(字段已卸载)
    User->>Form: 点击提交
    Form->>useForm: validateFields()
    useForm->>useForm: finalValueNamePathList排除已卸载字段
    useForm->>Store: getFieldsValue(finalValueNamePathList)
    Store-->>useForm: 返回表单值(仅活跃字段)
    useForm->>Form: onFinish(values)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

需要特别关注的区域:

  • src/useForm.ts 中getFieldEntitiesForNamePathList的返回类型及调用点的适配,特别是对INVALIDATE_NAME_PATH占位符的处理逻辑
  • finalValueNamePathList的引入和维护,确保在getFieldsValue、validateFields、getFieldsError等方法中的一致性
  • onValuesChange回调中allValues的计算和聚合逻辑,需验证与changedValues的合并行为
  • Form.List子字段的名路径条件推送逻辑,确保动态卸载场景下的正确处理
  • tests/list.test.tsx 中新增测试的完整性验证,特别是isShow切换前后的字段值变化

Poem

🐰 列表字段舞翩跹,挂载卸载显灵动,
幽灵路径做标记,灵活实体守护城,
从此表单更聪慧,动态之美在心中。✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed PR标题"Form.List name 不在 onFinish 取值中"(意为"Form.List name 在 onFinish 中不被获取")与变更集的核心目的高度相关。从raw_summary可以看出,主要代码改动集中在src/useForm.ts中对getFieldsValue逻辑的重构,引入了finalValueNamePathList来正确处理Form.List项的字段值提取,这直接解决了标题描述的问题。标题具体明确地指出了缺陷场景(Form.List在onFinish时的值获取),避免了模糊或通用术语,足以让团队成员快速理解该PR的主要目的。虽然PR还包含文档、测试和接口更新等补充内容,但标题成功捕捉了核心变更意图。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@vercel
Copy link

vercel bot commented Sep 3, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
field-form Ready Ready Preview Comment Sep 29, 2025 0:38am

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.

Summary of Changes

Hello @crazyair, 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!

此拉取请求旨在解决 rc-field-form 中一个关键的表单值收集问题,即 Form.List 的名称在 onFinish 回调中未能正确获取。通过修改核心表单逻辑,确保即使列表中的字段被动态卸载,表单也能准确地捕获所有相关数据。此外,还引入了一个新的示例来验证并展示此修复。

Highlights

  • 修复 Form.List 名称在 onFinish 中取值不正确的问题: 解决了当 Form.List 中的字段被条件渲染或卸载时,其名称无法正确包含在 onFinish 回调返回的值中的问题。
  • 新增 Form.List 卸载示例: 添加了一个新的文档和示例,用于演示和测试 Form.List 在其内部字段被卸载时的行为,确保数据收集的正确性。
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.

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 issue 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

此拉取请求旨在修复当 Form.List 中的字段被卸载后,其旧值仍会包含在 onFinish 回调的表单值中的问题。核心改动是在 validateFields 方法中,当收集所有字段路径用于最终取值时,跳过 Form.List 自身的实体,仅依赖其已挂载的子字段实体来构建值。这能正确处理字段卸载的场景。然而,这个修复引入了一个严重的问题:当 Form.List 为空数组时,它在 onFinish 的结果中会丢失。我已经就此问题在 src/useForm.ts 中添加了具体的审查评论。

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 (6)
src/useForm.ts (2)

1003-1011: 确保返回值与 “不包含 List 名称” 目标一致并覆盖测试

此处 returnPromise 最终通过 this.getFieldsValue(namePathList) 生成 values。由于上面已跳过 List 容器,namePathList 仅包含叶子字段,最后合并出的对象会包含 users 的值树,但不会把 List 自身当作字段实体返回,符合预期。建议新增一个用例覆盖:

  • 表单含 Form.List name="users",仅选中子字段时,onFinish(values) 中没有单独的 “List 容器字段” 项,但 values.users 的数组结构完整。

我可以基于现有测试框架起草一个最小复现用例。


309-351: getFieldsValue 的 List 过滤语义与 validateFields 对齐性

这里在 strict 与非 strict 下分别跳过 isListisListField。从行为上看与本次改动一致,但建议在源码注释中明确两者差异(List 容器 vs. List 子字段),避免后续维护者误用;同时补一条单测覆盖 getFieldsValue({ strict: true }) 与默认模式的差异,特别是在条件卸载子字段时的表现。

docs/demo/list-unmount.md (1)

1-3: 标题与其他示例保持命名风格一致

建议将小写的 ## list 调整为 ## List(或中文标题,如“列表:条件卸载字段”),与文档其它章节风格统一,便于检索。

docs/examples/list-unmount.tsx (3)

25-25: 演示区块可读性小优化

<Form.Field shouldUpdate> 直接渲染 JSON 字符串可读性一般,建议包裹在 <pre> 以保留缩进格式,或使用一个只读文本区域,便于对比 strict 与非 strict 的差异。

-        <Form.Field shouldUpdate>{() => JSON.stringify(form.getFieldsValue(), null, 2)}</Form.Field>
+        <Form.Field shouldUpdate>
+          {() => <pre>{JSON.stringify(form.getFieldsValue(), null, 2)}</pre>}
+        </Form.Field>

33-41: 利用 strict 对比“已注册字段 vs. 保留值”的效果非常好,建议在示例内补一行注释说明意图

当前示例通过条件卸载 age 字段并对比 getFieldsValue()getFieldsValue({ strict: true }),很好地演示了差异。为减少读者困惑,建议在此处添加一句注释说明:当 age 被卸载时,默认模式仍会返回保留的值,而 strict 只返回当前已挂载字段的值。


47-49: 按钮文案更明确一些

将“隐藏”调整为“隐藏/显示年龄”或增加 aria-pressed,对可读性与无障碍更友好。

-        <button type="button" onClick={() => setIsShow(c => !c)}>
-          隐藏
-        </button>
+        <button
+          type="button"
+          aria-pressed={!isShow}
+          onClick={() => setIsShow(c => !c)}
+        >
+          隐藏/显示年龄
+        </button>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2b0f66b and e37a002.

📒 Files selected for processing (3)
  • docs/demo/list-unmount.md (1 hunks)
  • docs/examples/list-unmount.tsx (1 hunks)
  • src/useForm.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
docs/examples/list-unmount.tsx (1)
tests/common/InfoField.tsx (1)
  • Input (9-11)
🔇 Additional comments (2)
src/useForm.ts (1)

924-926: 验证 Form.List 容器定向校验兼容性
本地运行完整测试并确认以下场景符合预期:

  • 调用 validateFields(['users']) 且 recursive: false 时是否跳过子项
  • recursive: true 或传入父/子路径时的校验行为
    在文档中明确说明不支持对 List 容器直接配置校验规则。
docs/examples/list-unmount.tsx (1)

1-5: 示例组件依赖已存在
已在 docs/examples/components 下找到 Input.tsxLabelField.tsx,文档站构建不会因缺失此处组件而失败。

@codecov
Copy link

codecov bot commented Sep 4, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.53%. Comparing base (0ec1a4e) to head (1d60c03).
⚠️ Report is 5 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #761   +/-   ##
=======================================
  Coverage   99.53%   99.53%           
=======================================
  Files          19       19           
  Lines        1289     1297    +8     
  Branches      320      322    +2     
=======================================
+ Hits         1283     1291    +8     
  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.

@zombieJ
Copy link
Member

zombieJ commented Sep 5, 2025

@gemini-code-assist Review it

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 中,已卸载的字段仍然会被包含在 onFinishvalues 中的问题。通过在 useForm.ts 中改用 getFieldsValue({ strict: true }),确保了在表单校验成功后,只收集已挂载字段的值,正确地解决了这个问题。新增的 list-unmount.tsx 示例和相关文档非常棒,清晰地展示了修复效果。

不过,这个修改也可能改变了 validateFields 的行为,它现在总是返回所有字段的值,而不是像以前一样只返回被校验字段的值。我在代码中留了一条评论,对此进行了更详细的说明,并指出了成功和失败路径下取值逻辑可能存在的不一致性。请查看。

@zombieJ
Copy link
Member

zombieJ commented Sep 17, 2025

@gemini-code-assist, pls help to CR again

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 在动态表单场景下,因列表项卸载导致 onFinish 回调中表单值不正确的问题。同时添加了对应的文档和示例。

代码改动主要在 src/useForm.tsvalidateFields 方法中,通过避免重复添加列表字段路径来解决问题。

整体来看,PR 的目标明确,修复是有效的。我有一个关于路径匹配逻辑的建议,希望能让代码更健壮。

@crazyair
Copy link
Contributor Author

@gemini-code-assist Review it

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 中动态卸载字段时 onFinish 可能获取到不正确值的问题。核心改动在 useForm.ts 中,通过调整 validateFields 方法里的字段收集逻辑,避免了列表字段和其子字段路径被重复添加,从而保证了取值的正确性。同时,PR 也新增了对应的单元测试和文档示例,覆盖了修复的场景。整体来看,代码改动清晰,测试和文档补充也很到位。我在 useForm.ts 中留下了一条关于代码健壮性的建议,旨在提高代码的长期可维护性,请查阅。

src/useForm.ts Outdated
if (!provideNameList) {
namePathList.push(field.getNamePath());
if (field.isList() && namePathList.some(name => matchNamePath(name, fieldNamePath, true))) {
removeListNameStrList.push(fieldNamePath.toString());
Copy link
Member

Choose a reason for hiding this comment

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

这个逻辑很奇怪,这里 matchNamePath 一次后,下面又从列表里匹配一遍。
应该是提取一个 filledPathList 专门存需要留档的路径出来,避免多轮遍历。

Copy link
Contributor Author

Choose a reason for hiding this comment

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

要用2个 list吗?也行吧,就是 push 的地方要写好几处地方,比较麻烦。

我现在实现的,就是单纯记录 List 这层的 name,然后在提交时候过滤。

@zombieJ
Copy link
Member

zombieJ commented Sep 28, 2025

@gemini-code-assist pls help to review again and provide more detail action.

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 中动态卸载的字段值仍会出现在 onFinish 回调中的问题。实现方式是通过在 validateFields 方法中区分“需要校验的字段列表”和“最终提交时需要取值的字段列表”,确保在提交时只包含当前已挂载的字段值。

改动逻辑清晰,并且通过新增的示例代码和单元测试充分覆盖了修复的场景,确保了代码质量。我对其中一处实现的复杂度和潜在性能问题提出了改进建议,但总体而言,这是一次高质量的提交。

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f2f069 and 4e69d82.

📒 Files selected for processing (2)
  • src/useForm.ts (3 hunks)
  • tests/list.test.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/useForm.ts
🧰 Additional context used
🧬 Code graph analysis (1)
tests/list.test.tsx (3)
tests/common/InfoField.tsx (1)
  • Input (9-11)
src/Field.tsx (1)
  • render (660-681)
tests/common/timeout.ts (1)
  • timeout (3-7)

@vercel
Copy link

vercel bot commented Oct 29, 2025

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

A member of the Team first needs to authorize it.

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

Caution

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

⚠️ Outside diff range comments (2)
src/useForm.ts (2)

323-354: 填充空 List 的判定应更精确

当前用 !getValue(...) 判空会把 null/0/'' 等“假值”误判。建议仅在 undefined 时填充 [],避免语义偏差。

-    listNamePaths.forEach(namePath => {
-      if (!getValue(mergedValues, namePath)) {
-        mergedValues = setValue(mergedValues, namePath, []);
-      }
-    });
+    listNamePaths.forEach(namePath => {
+      if (getValue(mergedValues, namePath) === undefined) {
+        mergedValues = setValue(mergedValues, namePath, []);
+      }
+    });

1018-1033: 对齐 validateFields 成功/失败返回结构

成功路径返回 getFieldsValue(finalValueNamePathList),而失败路径返回 getFieldsValue(namePathList),两者结构不一致,容易踩坑。建议失败路径也改为 finalValueNamePathList

-        return Promise.reject({
-          message: errorMessage,
-          values: this.getFieldsValue(namePathList),
+        return Promise.reject({
+          message: errorMessage,
+          values: this.getFieldsValue(finalValueNamePathList),
           errorFields: errorList,
           outOfDate: this.lastValidatePromise !== summaryPromise,
         });
♻️ Duplicate comments (1)
src/useForm.ts (1)

919-945: 关于 finalValueNamePathList 的构建建议补注释

这里对 Form.List 父路径做了排除,仅在不存在子字段时才纳入 finalValueNamePathList。建议加一行注释阐明:该列表仅用于“最终值收集”,避免同时包含父 List 与其子字段导致重复/覆盖问题,便于维护者理解上下文。

🧹 Nitpick comments (4)
src/interface.ts (1)

120-124: 命名与注释可读性建议

属性名使用全大写在接口字段中不常见,容易与常量混淆;且 “Mask as invalidate” 语义略生硬。建议改为更贴近语义的驼峰命名与注释,降低心智负担(保持向后兼容可先双写再迁移)。

-  /**
-   * Mask as invalidate.
-   * This will filled when Field is removed but not updated in render yet.
-   */
-  INVALIDATE_NAME_PATH?: InternalNamePath;
+  /**
+   * Mark this entity as a placeholder for an invalidated field.
+   * Filled when the Field has been removed but render has not updated yet.
+   */
+  invalidatedNamePath?: InternalNamePath;

若已在其余文件使用该字段,可先保留旧名并标注废弃,后续统一替换。

src/utils/valueUtil.ts (1)

23-31: 为 newStore 明确类型并微调循环

避免 {} 触发隐式 any,顺带用 for‑of 减少中间数组与闭包开销。

-export function cloneByNamePathList(store: Store, namePathList: InternalNamePath[]): Store {
-  let newStore = {};
-  namePathList.forEach(namePath => {
-    const value = getValue(store, namePath);
-    newStore = setValue(newStore, namePath, value);
-  });
-
-  return newStore;
-}
+export function cloneByNamePathList(store: Store, namePathList: InternalNamePath[]): Store {
+  let newStore: Store = {};
+  for (const namePath of namePathList) {
+    const value = getValue(store, namePath);
+    newStore = setValue(newStore, namePath, value);
+  }
+  return newStore;
+}
tests/list.test.tsx (1)

1015-1044: 补充空列表回归用例,防止再次回归

为确保当 Form.List 为空时仍返回 [](而非缺失或 undefined),建议增加专门测试用例。

+  it('empty Form.List should be kept as [] in getFieldsValue and onFinish', async () => {
+    const onFinish = jest.fn();
+    const formRef = React.createRef<FormInstance>();
+    const { queryByTestId } = render(
+      <Form ref={formRef} initialValues={{ users: [] }} onFinish={onFinish}>
+        <Form.List name="users">{() => null}</Form.List>
+        <button type="submit" data-testid="submit">Submit</button>
+      </Form>,
+    );
+    expect(formRef.current?.getFieldsValue()).toEqual({ users: [] });
+    fireEvent.click(queryByTestId('submit')!);
+    await act(async () => { await timeout(); });
+    expect(onFinish).toHaveBeenCalledWith({ users: [] });
+  });
src/useForm.ts (1)

787-791: onValuesChange 的合并可能冗余

updateStore 已在前面完成,this.getFieldsValue() 理论上可读到最新值;再次 merge 多一步拷贝。若无特别场景(例如 getFieldsValue 过滤导致缺项),可直接传 this.getFieldsValue(),以减少一次对象合并及内存分配。若确需保底,请在注释中说明原因。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c884da and 976b905.

📒 Files selected for processing (6)
  • src/Form.tsx (1 hunks)
  • src/List.tsx (1 hunks)
  • src/interface.ts (1 hunks)
  • src/useForm.ts (9 hunks)
  • src/utils/valueUtil.ts (1 hunks)
  • tests/list.test.tsx (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/Form.tsx
🧰 Additional context used
🧬 Code graph analysis (2)
tests/list.test.tsx (3)
src/interface.ts (1)
  • FormInstance (262-284)
tests/common/InfoField.tsx (1)
  • Input (9-11)
tests/common/timeout.ts (1)
  • timeout (3-7)
src/useForm.ts (2)
src/interface.ts (3)
  • FieldEntity (96-125)
  • NamePath (7-7)
  • InternalNamePath (6-6)
src/utils/valueUtil.ts (5)
  • cloneByNamePathList (23-31)
  • getNamePath (15-17)
  • getValue (6-6)
  • setValue (6-6)
  • matchNamePath (53-67)
🔇 Additional comments (3)
src/List.tsx (1)

4-4: 变更确认

仅导入来源调整,无行为变化,整体 LGTM。

tests/list.test.tsx (2)

599-602: 隔离断言噪音的好做法

在触发 remove 之前对 onValuesChange 执行 mockReset() 可以有效隔离先前调用,便于只断言当次变更,赞。同类用例可复用此手法。


942-1013: 覆盖“卸载字段不应出现在提交值”场景,赞

“list unmount” 用例验证了条件卸载后 onFinishgetFieldsValue() 的取值一致性,匹配 PR 目标,LGTM。

@zombieJ
Copy link
Member

zombieJ commented Oct 29, 2025

@gemini-code-assist 帮忙 CR 一下代码,看看有没有什么 edge case 没有处理

1 similar comment
@zombieJ
Copy link
Member

zombieJ commented Oct 29, 2025

@gemini-code-assist 帮忙 CR 一下代码,看看有没有什么 edge case 没有处理

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 976b905 and 1d60c03.

📒 Files selected for processing (1)
  • src/interface.ts (2 hunks)

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 中已卸载字段仍然存在于 onFinish 的返回值的 bug,做得很好。相关的逻辑修改看起来是合理的,并且通过新增的示例和单元测试,覆盖了核心场景,保证了修复的有效性。

我发现了一个潜在的严重问题和一处可以改进的地方:

  1. src/useForm.ts 中,onValuesChange 回调中使用了深合并(merge)来生成 allValues,这在处理数组删除操作时可能会导致不正确的结果。
  2. 在新的示例文件 docs/examples/list-unmount.tsx 中,使用了已被废弃的 strict: true 选项,这可能会让使用者感到困惑。

除此之外,其他部分的修改看起来都很不错。

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 在动态挂载/卸载字段时的值的处理逻辑,确保 onFinish 能获取到正确的表单值,并完善了对复杂列表结构的支持。同时,添加了相应的示例和测试用例,并废弃了 getFieldsValue 中的 strict 选项。

整体来看,这些改动提升了表单库的稳定性和易用性。我发现了一个核心逻辑中可能存在的依赖字段处理顺序的 bug,这在某些情况下可能导致 onFinish 的值不正确。此外,新添加的示例中使用了已被废弃的 API 选项。具体细节请查看我的评论。

@zombieJ zombieJ merged commit ad4256d into react-component:master Oct 29, 2025
7 of 8 checks passed
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.

2 participants