Skip to content

fix: restore load switcher after clearing search#657

Open
duqigit wants to merge 2 commits into
react-component:masterfrom
duqigit:fix-load-data-switcher-after-search-clear
Open

fix: restore load switcher after clearing search#657
duqigit wants to merge 2 commits into
react-component:masterfrom
duqigit:fix-load-data-switcher-after-search-clear

Conversation

@duqigit

@duqigit duqigit commented Jun 6, 2026

Copy link
Copy Markdown

修复 ant-design 中反馈的 TreeSelect 异步加载问题:ant-design/ant-design#55675

当用户在 TreeSelect 中搜索后再清空搜索内容时,异步节点仍然会被渲染成 noop switcher,导致原本用于展开/触发 loadData 的入口没有恢复,用户无法继续加载该节点。

这个修改会在清空搜索后恢复异步节点正常的加载/展开 switcher,同时保持搜索过程中不触发 loadData 的现有行为。

Summary by CodeRabbit

  • Bug Fixes

    • 修复树形选择器在搜索后清空时保持加载开关状态的问题
    • 优化搜索状态下的节点展开/收起管理,提升展开键一致性
  • Tests

    • 新增用例验证清空搜索后加载开关仍保留且在切换时会触发异步加载行为

@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

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

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Need an answer fast? Review this PR in Change Stack to ask focused questions about the PR or a changed range.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a6caa2fe-6560-4285-a293-31f05413bcb7

📥 Commits

Reviewing files that changed from the base of the PR and between b1e1947 and c4fddc0.

📒 Files selected for processing (2)
  • src/OptionList.tsx
  • tests/Select.loadData.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/Select.loadData.spec.tsx
  • src/OptionList.tsx

Walkthrough

重写 OptionList 中 mergedExpandedKeys 的 useMemo 分支与依赖,并收窄 hasLoadDataFn 的 memo 比较为仅基于 searchValue;新增测试验证清空搜索值后 load switcher 的可见性与 loadData 调用语义。

Changes

搜索与懒加载状态管理

Layer / File(s) Summary
mergedExpandedKeys 分支与依赖更新
src/OptionList.tsx
重写 mergedExpandedKeys 的计算:优先使用 treeExpandedKeys,否则根据 searchValue/searchExpandedKeysloadDatatreeDefaultExpandAll 决定是否回退到 `expandedKeys
hasLoadDataFn memo 比较收窄
src/OptionList.tsx
将 hasLoadDataFn 的 useMemo 依赖简化为仅包含 searchValue,并将自定义比较函数收窄为仅比较 preSearchValue !== nextSearchValue
懒加载切换器状态验证
tests/Select.loadData.spec.tsx
新增测试 keeps load switcher after clearing search value:验证清空搜索值后 loadData 不触发、load switcher 仍存在且 noop switcher 不出现;点击 close switcher 后 loadData 被调用一次。

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • react-component/tree-select#599: Main PR and PR #599 both modify src/OptionList.tsx’s hasLoadDataFn/loadData memo logic to change behavior based on searchValue, with related tests/Select.loadData.spec.tsx coverage around keeping the load switcher/sync behavior.
  • react-component/tree-select#592: Both PRs modify src/OptionList.tsx search-mode logic—specifically the memoized expanded-key handling and the loadData*/search-dependent behavior in OptionList, so the changes overlap at the same code paths.
  • react-component/tree-select#576: Both PRs modify src/OptionList.tsx’s search-related useMemo logic for expandedKeys/loadData handling—main PR rewrites mergedExpandedKeys and tightens hasLoadDataFn updates, while the retrieved PR changes loadData selection via a new loadDataFun to prevent incorrect loading during search state changes. ****

Suggested reviewers

  • zombieJ

Poem

🐰 我在树下跳又蹦,
搜索来时键儿跟随踪;
清空一回它仍在,
懒加载静候不慌张;
小兔记录,代码轻欢腾。

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题清晰准确地概括了主要改动:修复在清除搜索后恢复加载开关的问题。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

src/OptionList.tsx

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

tests/Select.loadData.spec.tsx

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.


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 gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request updates the expanded keys logic in OptionList.tsx to correctly handle cases when clearing the search value, specifically when loadData is provided and treeDefaultExpandAll is false. It also simplifies the search value comparison logic. A corresponding test case has been added in Select.loadData.spec.tsx to ensure the load switcher is preserved after clearing the search value. There are no review comments to address.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
tests/Select.loadData.spec.tsx (1)

47-69: ⚡ Quick win

考虑增强测试覆盖:验证清空搜索后的实际加载行为

当前测试验证了清空搜索后加载切换器(load switcher)的存在性,这对于捕获回归问题已经足够。但是,测试没有验证点击该切换器是否真正触发 loadData 回调,这是修复的完整功能验证的一部分。

建议考虑添加以下测试步骤以提高覆盖率:

💡 扩展测试覆盖的建议

在 line 68 之后添加:

// 验证清空搜索后点击加载切换器能够触发 loadData
fireEvent.click(container.querySelector('.rc-tree-select-tree-switcher_close')!);
await act(async () => {
  await Promise.resolve();
});
expect(loadData).toHaveBeenCalledTimes(1);

这将确保修复不仅恢复了切换器的显示,还恢复了其完整的加载功能。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/Select.loadData.spec.tsx` around lines 47 - 69, Extend the existing
test for TreeSelect to also assert that clicking the load switcher triggers the
loadData callback: after the existing assertions, query the
'.rc-tree-select-tree-switcher_close' element, fireEvent.click on it, wrap any
async resolution in act(async () => { await Promise.resolve(); }), then assert
expect(loadData).toHaveBeenCalledTimes(1); this ensures the TreeSelect loadData
handler (passed as loadData prop) is actually invoked when the switcher is
clicked.
src/OptionList.tsx (1)

322-327: ⚡ Quick win

确认 hasLoadDataFn 依赖项的必要性

hasLoadDataFnuseMemo 依赖项包含 [searchValue, treeExpandedKeys || expandedKeys],但自定义比较函数仅检查 searchValue 是否变化,完全忽略第二个依赖项。

如果第二个依赖项不影响重新计算逻辑,建议从依赖数组中移除它以提高代码清晰度:

♻️ 简化依赖项的建议
 const hasLoadDataFn = useMemo(
   () => (searchValue ? false : true),
-  [searchValue, treeExpandedKeys || expandedKeys],
+  [searchValue],
   ([preSearchValue], [nextSearchValue]) => preSearchValue !== nextSearchValue,
 );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/OptionList.tsx` around lines 322 - 327, The useMemo for hasLoadDataFn
declares dependencies [searchValue, treeExpandedKeys || expandedKeys] but the
custom comparator only compares searchValue, so remove the unused second
dependency and the now-unnecessary eslint-disable; update the useMemo call for
hasLoadDataFn to depend solely on searchValue (and keep the comparator that
compares previous vs next searchValue) or alternatively expand the comparator to
include treeExpandedKeys/expandedKeys if those should trigger
recomputation—locate the hasLoadDataFn useMemo and either remove
"treeExpandedKeys || expandedKeys" from the deps array and delete the
eslint-disable-next-line, or adjust the comparator to compare that second value
as well.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/OptionList.tsx`:
- Around line 322-327: The useMemo for hasLoadDataFn declares dependencies
[searchValue, treeExpandedKeys || expandedKeys] but the custom comparator only
compares searchValue, so remove the unused second dependency and the
now-unnecessary eslint-disable; update the useMemo call for hasLoadDataFn to
depend solely on searchValue (and keep the comparator that compares previous vs
next searchValue) or alternatively expand the comparator to include
treeExpandedKeys/expandedKeys if those should trigger recomputation—locate the
hasLoadDataFn useMemo and either remove "treeExpandedKeys || expandedKeys" from
the deps array and delete the eslint-disable-next-line, or adjust the comparator
to compare that second value as well.

In `@tests/Select.loadData.spec.tsx`:
- Around line 47-69: Extend the existing test for TreeSelect to also assert that
clicking the load switcher triggers the loadData callback: after the existing
assertions, query the '.rc-tree-select-tree-switcher_close' element,
fireEvent.click on it, wrap any async resolution in act(async () => { await
Promise.resolve(); }), then assert expect(loadData).toHaveBeenCalledTimes(1);
this ensures the TreeSelect loadData handler (passed as loadData prop) is
actually invoked when the switcher is clicked.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5f4cc9b1-8253-4fd9-9dc1-b57a770822dc

📥 Commits

Reviewing files that changed from the base of the PR and between 34b4676 and b1e1947.

📒 Files selected for processing (2)
  • src/OptionList.tsx
  • tests/Select.loadData.spec.tsx

Comment thread src/OptionList.tsx
Comment on lines +139 to +142
if (searchExpandedKeys && loadData && !treeDefaultExpandAll) {
return expandedKeys || [];
}
return expandedKeys;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
if (searchExpandedKeys && loadData && !treeDefaultExpandAll) {
return expandedKeys || [];
}
return expandedKeys;
return expandedKeys || [];

这里和直接这样有啥区别?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

这里主要差异在 treeDefaultExpandAll 场景。
初始化时如果没有传 treeDefaultExpandedKeys,expandedKeys 是 undefined。直接 return expandedKeys || [] 会返回 [],下游 Tree 收到 expandedKeys={[]} 后会进入受控展开状态,defaultExpandAll 就不会生效,所以默认展开会失效。

@duqigit duqigit requested a review from afc163 June 8, 2026 10:04
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