Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: supplement maxCount logic for complicated cases #602

Merged
merged 13 commits into from
Dec 24, 2024

Conversation

aojunhao123
Copy link
Contributor

@aojunhao123 aojunhao123 commented Dec 5, 2024

TreeSelect maxCount 功能优化

修复了 TreeSelect 组件在设置 maxCount 时对树形结构处理的问题,使其能够正确处理父子节点关系和树的传导规则。

主要改动

  • 修复了设置 maxCount 时父节点选择的问题
  • 优化了节点禁用状态的计算逻辑,当选中会导致超出 maxCount 限制时正确禁用节点
  • 改进了对禁用节点的处理,正确实现树的传导规则
  • 根据不同的 showCheckedStrategy 策略准确计算显示值数量

具体改进

  1. 父节点选中时会考虑其子节点数量,提前禁用可能导致超出 maxCount 的节点
  2. 遵循树的传导规则计算可选节点
  3. 在节点遍历时正确处理禁用状态
  4. 保持已选中节点始终可选
  5. 针对不同的显示策略准确计算显示值数量:
    • SHOW_ALL:计算所有选中节点
    • SHOW_CHILD:仅计算叶子节点

相关问题

修复了以下场景的问题:

  1. 当父节点包含大量子节点时,选中父节点可能导致超出 maxCount 限制
  2. 在不同显示策略下,maxCount 的计算不准确
  3. 已选中节点被错误禁用的问题

Summary by CodeRabbit

Summary by CodeRabbit

  • 新功能

    • TreeSelect 组件中引入了最大选择数量 (maxCount) 和剩余选择数量 (leftMaxCount) 属性。
    • 更新了 OptionList 组件的节点选择逻辑,增强了对禁用状态的管理。
    • 在示例中新增了禁用节点的支持。
    • 新增了针对复杂树结构的测试用例,以验证最大选择数量的处理。
    • 添加了警告机制,以提示不兼容的选中策略和最大选择数量设置。
  • bug 修复

    • 改进了选项选择逻辑,以确保在多选模式下不会超过最大选择数量。

Copy link

vercel bot commented Dec 5, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
tree-select ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 24, 2024 3:32am

Copy link

coderabbitai bot commented Dec 5, 2024

Walkthrough

此次更改涉及多个组件的修改,主要集中在 TreeSelectOptionListTreeSelectContext 中。引入了 maxCountleftMaxCount 两个新属性,以增强选择逻辑和上下文的可配置性。OptionList 组件的节点选择逻辑经过改进,确保在选择过程中遵循最大选择数量的限制。同时,treeData 结构在示例文件中也进行了调整,增加了禁用节点的功能。

Changes

文件路径 更改摘要
examples/mutiple-with-maxCount.tsx treeData 结构中添加了禁用节点,更新了节点的子项。保留了 showCheckedStrategy 的注释。
src/OptionList.tsx 引入了新导入 FieldNames,增强了选择逻辑,更新了 nodeDisabled 函数以支持最大选择数量,更新了 useEffect 钩子以清除缓存。
src/TreeSelect.tsx 更新了 TreeSelectContext,添加了 mergedMaxCountleftMaxCount,改进了选择逻辑和状态管理。
src/TreeSelectContext.ts TreeSelectContextProps 接口中移除了 displayValuesisOverMaxCount,添加了 leftMaxCountleafCountOnlyvalueEntities 属性。
src/utils/warningPropsUtil.ts 更新了 warningProps 函数的参数类型,添加了 showCheckedStrategymaxCount 属性,并增加了新的警告条件。
tests/Select.maxCount.spec.tsx 新增了测试套件,验证 TreeSelect 组件在复杂树结构下的最大选择数量行为。包括两个测试用例,确保选择逻辑符合预期。

Suggested reviewers

  • zombieJ

兔子欢快跳跃,代码更新真妙,
树形选择更灵活,禁用节点不再烦恼。
最大选择数把控,策略显示更明了,
让我们一起欢庆,代码世界更美好! 🐰✨

Tip

CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command @coderabbitai generate docstrings to have CodeRabbit automatically generate docstrings for your pull request. We would love to hear your feedback on Discord.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c4b2e13 and d8661d6.

📒 Files selected for processing (1)
  • tests/Select.warning.spec.js (1 hunks)
🔇 Additional comments (3)
tests/Select.warning.spec.js (3)

75-80: 测试覆盖率良好,警告信息断言合理。

此处在使用 maxCount 与 showCheckedStrategy=SHOW_ALL、treeCheckStrictly=false 的组合时,测试能够完整捕获到预期的警告信息,能够有效提升对警告逻辑的回归测试覆盖率。


82-87: 确保在多种组合策略下对警告信息进行验证。

此处再一次针对 maxCount 与 showCheckedStrategy=SHOW_PARENT 的组合进行测试,能够进一步确保不同策略下触发警告的逻辑一致且功能正常。


89-94: 良好地验证了在特定条件下不触发警告。

此处通过设置 treeCheckStrictly=true 并与 showCheckedStrategy=SHOW_ALL 一起使用,明确了不会出现警告信息。该测试场景有效确保在满足条件时不会产生误报。


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Dec 5, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (a1284ba) to head (d8661d6).
Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #602   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           16        16           
  Lines          561       598   +37     
  Branches       167       186   +19     
=========================================
+ Hits           561       598   +37     

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

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

🧹 Outside diff range and nitpick comments (2)
src/OptionList.tsx (1)

171-221: 建议优化 nodeDisabled 函数的可读性

当前的 nodeDisabled 函数逻辑较为复杂,嵌套深度较大,可能影响代码的可读性和维护性。建议将复杂的逻辑拆分为多个小函数,或在关键部分添加注释,以提高代码的可读性。

examples/mutiple-with-maxCount.tsx (1)

87-87: 考虑清理已注释的 showCheckedStrategy 属性

在第 87 行,showCheckedStrategy="SHOW_PARENT" 被注释掉。若不再需要,建议删除该注释代码;若需保留,建议添加说明以解释注释原因。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a1284ba and 6193365.

📒 Files selected for processing (4)
  • examples/mutiple-with-maxCount.tsx (2 hunks)
  • src/OptionList.tsx (3 hunks)
  • src/TreeSelect.tsx (2 hunks)
  • src/TreeSelectContext.ts (2 hunks)
🔇 Additional comments (4)
src/TreeSelect.tsx (2)

628-629: 确保在上下文中正确传递 maxCountshowCheckedStrategy

maxCountmergedShowCheckedStrategy 添加到 treeSelectContext 中,确保子组件能够访问并使用这些新添加的配置属性。


646-646: 在依赖项数组中包含 mergedShowCheckedStrategy

useMemo 的依赖项数组中添加 mergedShowCheckedStrategy,确保当该策略更改时,treeSelectContext 能够正确地重新计算和更新。

src/TreeSelectContext.ts (2)

4-4: 引入 CheckedStrategy 类型

'./utils/strategyUtil' 导入 CheckedStrategy,以便在接口中使用该类型,增强类型检查和代码可读性。


20-21: TreeSelectContextProps 接口中添加 maxCountshowCheckedStrategy 属性

TreeSelectContextProps 接口新增可选的 maxCountshowCheckedStrategy 属性,使上下文配置更灵活,支持最大选择数量和选择显示策略的定制。

src/OptionList.tsx Outdated Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (1)
tests/Select.maxCount.spec.tsx (1)

449-470: 建议将代码注释统一为英文

为了保持代码库的一致性和方便全球开发者理解,建议将测试代码中的中文注释翻译为英文。

Also applies to: 493-502

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c96aee2 and c8b2c92.

📒 Files selected for processing (5)
  • examples/mutiple-with-maxCount.tsx (2 hunks)
  • src/OptionList.tsx (3 hunks)
  • src/TreeSelect.tsx (3 hunks)
  • src/TreeSelectContext.ts (2 hunks)
  • tests/Select.maxCount.spec.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/TreeSelectContext.ts
  • examples/mutiple-with-maxCount.tsx
🧰 Additional context used
🪛 eslint
src/OptionList.tsx

[error] 178-178: 'fieldNames' is already declared in the upper scope on line 46 column 5.

(@typescript-eslint/no-shadow)

🔇 Additional comments (1)
tests/Select.maxCount.spec.tsx (1)

375-503: 测试用例正确地覆盖了复杂场景

新增的测试用例有效地验证了在复杂树结构下 maxCount 的行为,逻辑清晰,符合预期。

src/OptionList.tsx Outdated Show resolved Hide resolved
src/TreeSelect.tsx Outdated Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (1)
src/OptionList.tsx (1)

164-176: 建议优化缓存重置逻辑

当前实现在 checkedKeysmaxCount 变化时会清空整个缓存。考虑以下优化建议:

  1. 可以只清除受影响的缓存项,而不是清空整个 Map
  2. 考虑添加缓存大小限制,避免在大型树结构中内存占用过大
  const resetCache = React.useCallback(() => {
-   disabledCacheRef.current.clear();
+   // 只清除受影响的缓存项
+   const affectedPrefix = `${checkedKeys.join(',')}-${maxCount}`;
+   for (const key of disabledCacheRef.current.keys()) {
+     if (key.includes(affectedPrefix)) {
+       disabledCacheRef.current.delete(key);
+     }
+   }
    lastCheckedKeysRef.current = [...checkedKeys];
    lastMaxCountRef.current = maxCount;
  }, [checkedKeys, maxCount]);
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c8b2c92 and ffe87e5.

📒 Files selected for processing (2)
  • src/OptionList.tsx (3 hunks)
  • src/TreeSelectContext.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/TreeSelectContext.ts
🔇 Additional comments (2)
src/OptionList.tsx (2)

12-16: 导入和上下文变更看起来不错!

新增的导入和上下文值很好地支持了 maxCount 和 showCheckedStrategy 的功能实现。

Also applies to: 53-54


192-226: ⚠️ Potential issue

性能优化警告:需要处理非虚拟列表场景

根据之前 @zombieJ 的评论,当前实现在未启用虚拟列表时可能会导致性能雪崩。建议:

  1. 在非虚拟列表场景下,实现节点懒加载机制
  2. 考虑使用 worker 线程处理复杂计算
  3. 实现节点计算结果的批量更新
  const nodeDisabled = useEvent((node: DataNode) => {
+   // 非虚拟列表场景下的性能优化
+   if (!virtual) {
+     const batchSize = 100;
+     const throttleMs = 16;
+     
+     // 实现节点计算的批量处理逻辑
+     // TODO: 添加具体实现
+   }
    
    // 原有逻辑保持不变
    const nodeValue = node[fieldNames.value];
    // ...
  });

src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
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

🧹 Outside diff range and nitpick comments (2)
src/TreeSelect.tsx (2)

Line range hint 89-89: 建议为 maxCount 属性添加 JSDoc 注释

为了提高代码的可维护性和使用体验,建议添加 JSDoc 注释来说明 maxCount 属性的用途、限制条件和使用示例。

建议添加如下注释:

+ /** 
+  * 最大可选择的节点数量
+  * @default undefined
+  */
  maxCount?: number;

Line range hint 391-476: 建议重构 onOptionSelect 函数以提高可维护性

当前的 onOptionSelect 函数职责过重,包含了选择逻辑、树形结构处理和 maxCount 限制等多个功能。建议将其拆分为更小的、职责单一的函数。

建议按照以下方式重构:

const canSelectMore = (newValue: SafeKey) => {
  if (!mergedMultiple || maxCount === undefined) {
    return true;
  }
  
  const newNodeCount = getNodeCount(newValue, keyEntities);
  return calculateSelectedCount + newNodeCount <= maxCount;
};

const handleTreeConduction = (newRawValues: SafeKey[], selected: boolean) => {
  const { missingRawValues, existRawValues } = splitRawValues(newRawValues);
  const keyList = existRawValues.map(val => valueEntities.get(val).key);
  
  const { checkedKeys } = selected
    ? conductCheck(keyList, true, keyEntities)
    : conductCheck(keyList, { checked: false, halfCheckedKeys: rawHalfCheckedValues }, keyEntities);
    
  return [...missingRawValues, ...checkedKeys.map(key => 
    keyEntities[key as SafeKey].node[mergedFieldNames.value])];
};

const onOptionSelect = (selectedKey: SafeKey, { selected, source }) => {
  const entity = keyEntities[selectedKey];
  const node = entity?.node;
  const selectedValue = node?.[mergedFieldNames.value] ?? selectedKey;

  if (!mergedMultiple) {
    triggerChange([selectedValue], { selected: true, triggerValue: selectedValue }, 'option');
    onSelect?.(selectedValue, fillLegacyProps(node));
    return;
  }

  if (selected && !canSelectMore(selectedValue)) {
    return;
  }

  const newRawValues = selected
    ? [...rawValues, selectedValue]
    : rawCheckedValues.filter(v => v !== selectedValue);

  const finalValues = treeConduction 
    ? handleTreeConduction(newRawValues, selected)
    : newRawValues;

  triggerChange(finalValues, { selected, triggerValue: selectedValue }, source || 'option');

  if (selected) {
    onSelect?.(selectedValue, fillLegacyProps(node));
  } else {
    onDeselect?.(selectedValue, fillLegacyProps(node));
  }
};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between ffe87e5 and 8f47675.

📒 Files selected for processing (2)
  • src/OptionList.tsx (3 hunks)
  • src/TreeSelect.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/OptionList.tsx
🔇 Additional comments (1)
src/TreeSelect.tsx (1)

Line range hint 4-4: 建议补充 maxCount 功能的测试用例

为确保 maxCount 功能在各种场景下的正确性,建议补充以下测试场景:

  1. 不同 showCheckedStrategy 策略下的 maxCount 限制
  2. 父子节点选择时的 maxCount 计数
  3. 取消选择时的状态恢复
  4. 边界条件测试(maxCount 为 0、1 等)

src/TreeSelect.tsx Outdated Show resolved Hide resolved
@zombieJ zombieJ self-assigned this Dec 20, 2024
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 (3)
src/OptionList.tsx (3)

12-12: 引入的 FieldNames 在本文件中未被使用
根据静态分析提示,FieldNames 当前未用到。若确无后续引用,可考虑移除该 import。

🧰 Tools
🪛 eslint

[error] 12-12: 'FieldNames' is defined but never used.

(@typescript-eslint/no-unused-vars)


15-15: formatStrategyValues 未被使用
和上一条相似,若无后续使用,建议删除 import,避免无用代码。

🧰 Tools
🪛 eslint

[error] 15-15: 'formatStrategyValues' is defined but never used.

(@typescript-eslint/no-unused-vars)


163-165: 通过 disabledCacheRef 提升节点禁用检查的性能
缓存机制可避免在大规模树中反复计算。此实现能提高渲染效率,思路不错。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f47675 and faa432b.

📒 Files selected for processing (5)
  • examples/mutiple-with-maxCount.tsx (2 hunks)
  • src/OptionList.tsx (3 hunks)
  • src/TreeSelect.tsx (4 hunks)
  • src/TreeSelectContext.ts (2 hunks)
  • src/utils/warningPropsUtil.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/mutiple-with-maxCount.tsx
🧰 Additional context used
🪛 eslint
src/OptionList.tsx

[error] 12-12: 'FieldNames' is defined but never used.

(@typescript-eslint/no-unused-vars)


[error] 15-15: 'formatStrategyValues' is defined but never used.

(@typescript-eslint/no-unused-vars)

🔇 Additional comments (13)
src/utils/warningPropsUtil.ts (4)

13-14: 解构新增属性 showCheckedStrategy、maxCount 的用途明确
这两个属性后续在文件中均有实际使用,逻辑一致性良好,无明显问题。


25-25: 无效对象检测逻辑看起来合理
使用 toArray(value).every(...) 确保 value 均为合法对象,有助于减少非标准结构传入的风险。


38-38: 空行变更
此处仅为空行,不影响功能,可忽略。


39-44: 对特定 showCheckedStrategy 提示不兼容 maxCount
在 SHOW_ALL 或 SHOW_PARENT 场景下禁止 maxCount,能有效避免策略冲突。此处警告信息清晰明确。

src/TreeSelectContext.ts (1)

19-23: 增加了 leftMaxCount、leafCountOnly、valueEntities 三个上下文字段
引入这些字段后,可在下游组件统一读取与“剩余可选数量”和“叶节点计数策略”有关的信息,设计思路清晰,可维护性提高。

src/OptionList.tsx (4)

51-53: 解构获取 leftMaxCount、leafCountOnly、valueEntities
这些属性通过 TreeSelectContext 提供,可配合节点选择逻辑在大规模树中正确应用 maxCount 和叶节点限制。实现思路合理。


166-172: 基于 leftMaxCount 的 useEffect 清理缓存
当可选择数量重新计算后,及时清理缓存可防止过时状态。逻辑完善,值得肯定。


173-195: getDisabledWithCache:综合判断节点子元素规模
通过 children 长度、已选节点等信息判断是否禁用,且采用缓存避免重复计算。整体实现对大树有较好扩展性。


197-216: nodeDisabled 函数内多分支判断可维持代码简洁性
对于已勾选节点直接 return false 并终止其余判断;当 leftMaxCount 不存在或大于零时再做判断。实现逻辑严谨,清晰易读。

src/TreeSelect.tsx (4)

411-421: mergedMaxCount 逻辑简化选项
仅在多选模式下且识别到特定策略时才生效,可减少无关场景的干扰,设计合理。


436-438: 在触发更新前校验是否超过 mergedMaxCount
此检查防止用户越过限制强行添加过多条目,保证组件行为符合 maxCount 规范。


632-635: leftMaxCount 的计算逻辑
基于当前已显示数量判断剩余可选数量,为后续子组件快速判断是否可选提供直接依据。


650-654: leafCountOnly 条件与 maxCount、treeCheckStrictly、treeCheckable 的联动
当启用 SHOW_CHILD 并禁用严格模式时,才采用叶节点计数,这能更准确地匹配业务需求。

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 (5)
src/OptionList.tsx (3)

162-170: 缓存实现合理,建议优化内存使用

缓存 disabled 状态的实现可以提高性能,但建议考虑以下优化:

  1. 在组件卸载时清理缓存
  2. 考虑设置缓存大小限制,避免内存持续增长

建议添加以下清理逻辑:

+ React.useEffect(() => {
+   return () => {
+     disabledCacheRef.current.clear();
+   };
+ }, []);

172-193: 建议增加输入验证

getDisabledWithCache 函数的实现逻辑正确,但建议增加以下安全检查:

  1. 验证 value 是否为有效值
  2. 验证 entity 是否存在
  3. 处理 children 为 undefined 的情况

建议修改如下:

 function getDisabledWithCache(node: DataNode) {
+  if (!node || !fieldNames.value) {
+    return false;
+  }
   const value = node[fieldNames.value];
   if (!disabledCacheRef.current.has(value)) {
     const entity = valueEntities.get(value);
+    if (!entity) {
+      return false;
+    }
-    const isLeaf = (entity.children || []).length === 0;
+    const children = entity.children || [];
+    const isLeaf = children.length === 0;

195-215: 建议完善函数文档

nodeDisabled 函数实现了复杂的禁用状态逻辑,建议添加详细的文档说明:

  1. 各个条件分支的判断依据
  2. 性能考虑说明
  3. 与 maxCount 的关系说明

建议添加如下注释:

+/**
+ * 计算节点是否应该被禁用
+ * @param node - 要检查的节点
+ * @returns {boolean} 是否禁用
+ * 
+ * 禁用逻辑:
+ * 1. 已选中的节点永远不禁用
+ * 2. 没有 maxCount 限制时不禁用
+ * 3. 剩余可选数量为 0 时禁用
+ * 4. 叶子节点计数模式下,根据缓存计算禁用状态
+ */
 const nodeDisabled = useEvent((node: DataNode) => {
tests/Select.maxCount.spec.tsx (1)

349-476: 建议增加更多测试场景

当前的复杂场景测试覆盖了基本情况,建议增加以下测试场景:

  1. 动态变更 maxCount 值的情况
  2. 搜索过滤后的选择限制
  3. 异步加载子节点的场景
  4. 边界值测试(maxCount 为 1 的特殊情况)

建议添加如下测试用例:

it('should handle dynamic maxCount changes', () => {
  const { rerender } = render(
    <TreeSelect
      treeData={complexTreeData}
      treeCheckable
      multiple
      maxCount={3}
    />
  );

  // 测试动态改变 maxCount
  rerender(
    <TreeSelect
      treeData={complexTreeData}
      treeCheckable
      multiple
      maxCount={2}
    />
  );
});
src/TreeSelect.tsx (1)

436-438: 建议优化 maxCount 检查时机

当前在 triggerChange 中检查 maxCount 限制可能会导致不必要的计算。建议将检查提前到 onOptionSelect 中进行。

建议重构为:

 const onOptionSelect = React.useCallback(
   (selectedKey: SafeKey, { selected, source }: { selected: boolean; source: SelectSource }) => {
+    // Early check for maxCount
+    if (mergedMaxCount && selected && rawValues.length >= mergedMaxCount) {
+      return;
+    }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between faa432b and b23bfc2.

📒 Files selected for processing (3)
  • src/OptionList.tsx (2 hunks)
  • src/TreeSelect.tsx (4 hunks)
  • tests/Select.maxCount.spec.tsx (1 hunks)
🔇 Additional comments (3)
src/OptionList.tsx (1)

50-52: 新增的上下文属性设计合理

新增的三个上下文属性很好地支持了 maxCount 的功能实现:

  • leftMaxCount: 用于追踪剩余可选数量
  • leafCountOnly: 控制节点计数策略
  • valueEntities: 提供节点关系访问
src/TreeSelect.tsx (2)

411-420: mergedMaxCount 计算逻辑清晰

mergedMaxCount 的计算考虑了多种场景:

  1. 多选模式
  2. 显示策略
  3. 严格检查模式
  4. 可选状态

实现逻辑清晰合理。


632-635: 上下文属性设计合理

新增的上下文属性设计合理:

  1. leftMaxCount 计算准确
  2. leafCountOnly 条件判断完整
  3. valueEntities 提供必要的数据支持

@zombieJ zombieJ merged commit b858a0c into react-component:master Dec 24, 2024
9 checks passed
@aojunhao123 aojunhao123 deleted the feat-maxCount-improve branch December 26, 2024 05:41
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