Skip to content

[WIP]fix:parent node not disabled when child nodes count greater than maxCount #642

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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

yellowryan
Copy link

@yellowryan yellowryan commented Apr 22, 2025

Related issue #53567

Before:
之前的计算逻辑是只判断当前节点的直接子节点是否disabled,然后计算其总数
image

导致计算出来的title为'1'对应的node未被正确的赋上disabled属性

2025-04-22.064749.mp4

After:
将未禁用状态下的非叶子节点的子节点也进行统计、计算

2025-04-22.162816.mp4

Summary by CodeRabbit

  • 优化
    • 改进了多层级树结构下可勾选叶子节点的统计逻辑,提升了节点可用状态的准确性。
    • 优化了示例中多选树选择组件的展示,简化了界面并调整了最大可选数量设置。

Copy link

vercel bot commented Apr 22, 2025

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 Apr 23, 2025 9:33am

Copy link

coderabbitai bot commented Apr 22, 2025

Walkthrough

此次更改针对 src/OptionList.tsxgetDisabledWithCache 函数的逻辑进行了调整。原有实现仅统计实体节点直接子节点中可勾选叶子节点的数量。新实现通过显式的深度优先遍历,递归遍历整个子树,统计所有符合条件(未禁用、未勾选、非 checkbox-disabled)的叶子节点数量,并引入了访问集合以避免循环引用,同时在计数超过 leftMaxCount 时提前终止遍历。其余逻辑,包括根据该数量是否超过 leftMaxCount 来缓存禁用状态,保持不变。示例中 mutiple-with-maxCount.tsx 的树结构被扩展并简化了部分 UI 组件,调整了初始状态和树节点层级。

Changes

文件/路径 变更摘要
src/OptionList.tsx 将直接子节点计数逻辑替换为基于栈的深度优先遍历,统计所有可勾选叶子节点数量,增加循环检测和提前终止。
examples/mutiple-with-maxCount.tsx 扩展树数据结构,调整初始状态,简化 UI,修改 TreeSelect 组件的 maxCount 和多选配置。

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant OptionList
    participant TreeEntity

    User->>OptionList: 调用 getDisabledWithCache(entity)
    OptionList->>OptionList: 使用栈进行深度优先遍历子节点
    OptionList->>TreeEntity: 访问每个子节点,判断是否叶子且可勾选
    OptionList-->>OptionList: 计数,超过 leftMaxCount 则提前终止
    OptionList-->>User: 返回禁用状态缓存结果
Loading

Possibly related PRs

Suggested reviewers

  • zombieJ

Poem

小兔跳进代码林,
叶子节点细细寻。
栈中遍历防循环,
数量超限早终止。
禁用状态更精准,
代码清新又灵动! 🐇🌿

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

examples/mutiple-with-maxCount.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

src/OptionList.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 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.
  • @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

@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)
src/OptionList.tsx (1)

181-205: 递归计数函数存在重复创建与深度遍历性能问题,可考虑优化

  1. getLeafCheckableCount 定义在 getDisabledWithCache 内部,每次计算都会重新创建函数;在大树和频繁调用场景(如滚动虚拟列表)中会带来不必要的 GC 压力。可将其提到外层并以参数注入所需上下文,或使用 useCallback 缓存。
  2. 当前递归会完整遍历子树,直到所有叶子统计完毕。若叶子数一旦超过 leftMaxCount,后续遍历已无意义,可及时 return count 或抛出标记提前终止,提高效率。
  3. 对极深层树结构,JS 递归有栈溢出的风险(> ~10k 递归深度);可以改用显式栈迭代保证安全。

示例改动(仅演示早停逻辑):

const getLeafCheckableCount = (
-  children: DataEntity<DataNode>[],
-): number => {
+  children: DataEntity<DataNode>[],
+  limit: number,
+): number => {
   return children.reduce((count, current) => {
+    if (count > limit) {      // 早停
+      return count;
+    }
     ...
-      return count + getLeafCheckableCount(currentEntity.children);
+      return count + getLeafCheckableCount(currentEntity.children, limit - count);
   }, 0);
 };
-const checkableChildrenCount = getLeafCheckableCount(entity.children);
+const checkableChildrenCount = getLeafCheckableCount(entity.children, leftMaxCount);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6fa2d68 and cdff8c1.

📒 Files selected for processing (1)
  • src/OptionList.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/OptionList.tsx (1)
src/interface.ts (1)
  • DataNode (6-10)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: WIP
🔇 Additional comments (1)
src/OptionList.tsx (1)

168-173: 缓存刷新条件可能遗漏 checkedKeys 变化

disabledCache 只在 leftMaxCount 变化时清空。如果 leftMaxCount 的计算并未随每一次勾选/取消勾选同步更新(取决于上层实现),那么在同一个 leftMaxCount 周期内用户改变勾选状态后,缓存的可选状态可能过期,导致父节点禁用/启用状态与实际剩余可选数量不一致。建议确认:

  1. leftMaxCount 是否一定随 checkedKeys 的变化而变化。
  2. 如不确定,可把 checkedKeys 也加入依赖,或在勾选操作后调用 setDisabledCache(new Map()) 以保证一致性。

);

const checkableChildrenCount = checkableChildren.length;
const getLeafCheckableCount = (children: DataEntity<DataNode>[]): number => {
Copy link
Member

Choose a reason for hiding this comment

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

这样会有性能问题,最好是收集可见区域的节点,通过染色来做标记。避免递归产生大量的性能损耗。

Copy link
Author

Choose a reason for hiding this comment

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

那是不是可以通过栈+染色的形式来进行一个优化

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)
examples/mutiple-with-maxCount.tsx (1)

67-69: onCheckChange 函数在当前示例中未被使用

onCheckChange 函数和 checkValue 状态在当前简化后的UI中似乎没有被使用到。由于只保留了一个 TreeSelect 组件,且该组件仅使用了 onChangevalue 属性,可以考虑移除这些未使用的代码。

-  const [checkValue, setCheckValue] = useState<string[]>();

-  const onCheckChange = (val: string[]) => {
-    setCheckValue(val);
-  };
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between cdff8c1 and fa85621.

📒 Files selected for processing (2)
  • examples/mutiple-with-maxCount.tsx (2 hunks)
  • src/OptionList.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/OptionList.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: WIP
🔇 Additional comments (3)
examples/mutiple-with-maxCount.tsx (3)

5-6: 将初始状态从预设值改为 undefined 是合理的调整

这里的修改将 valuecheckValue 的初始状态从预设数组改为 undefined,这样使得树选择组件初始时不预选任何节点,符合测试案例的需求。


24-43: 扩展树结构深度有助于更好地测试问题场景

添加更深层次的树结构非常有利于测试当子节点数量超过 maxCount 时父节点是否正确禁用的问题。这个5层深的结构能够充分验证PR中修复的功能。


77-80: 明确设置 multiple 和 maxCount 属性有助于突显问题

添加 multiple 属性并明确设置 maxCount={3} 使得示例更加聚焦于要解决的问题,有利于验证当子节点总数超过3个时父节点是否能正确禁用。

const currentEntity = stack.pop();
const currentValue = currentEntity.node[fieldNames.value];

if (visited.has(currentValue)) {
Copy link
Member

Choose a reason for hiding this comment

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

这个 visited 是在 getDisabledWithCache 里申明的,那每次进来都会是一个新的


if (isCurrentLeaf) {
if (!isDisabled) {
checkableCount++;
Copy link
Member

Choose a reason for hiding this comment

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

其实深度遍历的话可以考虑直接做个 dig function,然后计数器超过 maxCount 直接短路就行了。

Copy link

codecov bot commented Apr 23, 2025

Codecov Report

Attention: Patch coverage is 95.83333% with 1 line in your changes missing coverage. Please review.

Project coverage is 99.50%. Comparing base (6fa2d68) to head (b69ed2b).

Files with missing lines Patch % Lines
src/OptionList.tsx 95.83% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #642      +/-   ##
==========================================
- Coverage   99.83%   99.50%   -0.33%     
==========================================
  Files          16       16              
  Lines         593      611      +18     
  Branches      186      180       -6     
==========================================
+ Hits          592      608      +16     
- Misses          1        3       +2     

☔ 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.

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