Skip to content

Conversation

@zombieJ
Copy link
Member

@zombieJ zombieJ commented Jan 23, 2026

ref ant-design/ant-design#56049

当设置 open false 的时候,设置一个临时锁。在 open 生效后解锁,以保持 OptionList 渲染同步。以解决闪烁问题:

Before After
Kapture 2026-01-23 at 11 40 52 Kapture 2026-01-23 at 11 39 18

PS: jsdom 无法模拟,sad

Summary by CodeRabbit

发布说明

  • 优化改进
    • 改进了选项列表在开启/关闭状态转换期间的稳定性和状态管理机制。
    • 增强了服务端渲染(SSR)兼容性,确保初始渲染后正确处理开启状态。
    • 优化了并发选项更新期间的协调机制,防止转换过程中的冲突。

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

@vercel
Copy link

vercel bot commented Jan 23, 2026

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

Project Deployment Review Updated (UTC)
select Ready Ready Preview, Comment Jan 23, 2026 3:42am

@gemini-code-assist
Copy link

Summary of Changes

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

此拉取请求旨在解决 Ant Design BaseSelect 组件中存在的闪烁问题,该问题在 open 属性设置为 false 时出现。通过引入一个临时的锁定机制,确保 OptionList 组件在关闭选择器时能够同步渲染,从而提供更流畅的用户体验。

Highlights

  • 新增选项列表锁定机制: 引入了一个新的 lockOptions 状态,用于在特定条件下阻止 OptionList 组件的选项列表重新渲染。
  • 优化 useOpen Hook: useOpen Hook 现在返回 lockOptions 状态,并在关闭选择器时将其设置为 true,在打开或完成关闭动画后将其设置为 false
  • 改进 OptionList 渲染逻辑: OptionList 组件的 memoFlattenOptions useMemo 依赖项已更新,以利用 lockOptions。当 lockOptionstrue 时,即使 open 状态改变,选项列表也不会立即重新计算,从而避免了闪烁问题。
  • 上下文传递 lockOptions: BaseSelectContext 已更新,以通过上下文向子组件提供 lockOptions 状态。

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 23, 2026

概览

此更改为 useOpen 钩子引入了一个新的锁定机制,返回第三个元素 lockOptions 来协调选项在打开/关闭转换期间的更新。该值通过上下文传播到 BaseSelectOptionList 组件,改变了选项列表的重新计算时机。

变更

聚类 / 文件 变更摘要
核心钩子逻辑
src/hooks/useOpen.ts
useOpen 的公开 API 从返回二元组 [open, toggleOpen] 改为三元组 [open, toggleOpen, lockOptions]。新增 SSR 处理(通过 rendered 标志延迟状态暴露)和锁定机制,在打开/关闭转换期间协调选项更新。
上下文和接口更新
src/hooks/useBaseProps.ts
BaseSelectContextProps 接口添加 lockOptions: boolean 属性,扩展上下文的类型签名。
组件集成
src/BaseSelect/index.tsx, src/OptionList.tsx
BaseSelectuseOpen 获取 lockOptions 并将其注入上下文。OptionList 更新了 flattenOptions 的记忆化依赖,从依赖 flattenOptions 改为依赖 lockOptions,改变了选项列表的稳定性和重新计算逻辑。

序列图

sequenceDiagram
    participant User as 用户
    participant BaseSelect as BaseSelect 组件
    participant useOpen as useOpen 钩子
    participant OptionList as OptionList 组件
    participant Context as BaseSelectContext

    User->>BaseSelect: 点击触发打开选择器
    BaseSelect->>useOpen: 调用 toggleOpen()
    activate useOpen
    Note over useOpen: setLock(true)<br/>计算 nextOpenVal
    useOpen->>useOpen: 锁定启用,阻止选项更新
    useOpen->>BaseSelect: 返回 [open, toggleOpen, lockOptions=true]
    deactivate useOpen
    BaseSelect->>Context: 更新上下文 lockOptions=true
    OptionList->>Context: 读取 lockOptions=true
    Note over OptionList: flattenOptions 记忆化跳过<br/>(lockOptions=true 时不重新计算)
    useOpen->>useOpen: triggerEvent() 后清除锁
    useOpen->>BaseSelect: 返回 lockOptions=false
    BaseSelect->>Context: 更新上下文 lockOptions=false
    OptionList->>Context: 读取 lockOptions=false
    Note over OptionList: flattenOptions 可以安全<br/>重新计算和渲染
Loading

预估代码审查工作量

🎯 3 (中等) | ⏱️ ~25 分钟

可能相关的 PR

诗句

🐰 打开与锁定的舞蹈
选项们排成一队,
锁门关闭在转换时,
防止混乱的更新狂欢,
解锁后它们欢快地舞动!✨

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive 标题'enhance: support filter not change'过于简洁模糊,未能清晰传达主要变更内容。虽然涉及真实改动,但措辞不够具体,难以让团队成员通过标题快速理解核心改进目标。 建议调整标题为更具描述性的表述,例如'enhance: add lockOptions to prevent option list flicker during open/close',以更清晰地说明此PR的核心目的是解决选项列表闪烁问题。
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch optionLock

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.

@codecov
Copy link

codecov bot commented Jan 23, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.42%. Comparing base (d1aeb03) to head (e728820).

Additional details and impacted files
@@           Coverage Diff           @@
##           master    #1193   +/-   ##
=======================================
  Coverage   99.42%   99.42%           
=======================================
  Files          31       31           
  Lines        1219     1222    +3     
  Branches      412      412           
=======================================
+ Hits         1212     1215    +3     
  Misses          7        7           

☔ 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

@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 旨在通过引入一个锁来解决关闭 Select 时选项列表闪烁的问题,这个思路是正确的。useOpen hook 中的锁状态管理看起来没有问题。

然而,在 OptionList.tsx 中使用这个锁的方式似乎引入了一个严重的问题:它可能会导致搜索过滤功能失效。我在代码中留下了具体的审查意见和修改建议。请您关注一下这个 useMemo 的实现,确保在修复闪烁问题的同时,不会影响到现有的过滤功能。

Comment on lines 70 to 74
const memoFlattenOptions = useMemo(
() => flattenOptions,
[open, flattenOptions],
(prev, next) => next[0] && prev[1] !== next[1],
[open, lockOptions],
(prev, next) => next[0] && !next[1],
);

Choose a reason for hiding this comment

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

critical

这个 useMemo 的实现似乎会破坏搜索过滤功能。当前的逻辑是当下拉框打开且未锁定时(open && !lockOptions),memoFlattenOptions 将不会更新。这会导致用户在搜索时,选项列表不会刷新。

为了解决这个问题,同时保留修复闪烁的逻辑,我们可以修改 useMemo 的依赖和比较函数。我们希望仅在 lockOptionstrue 时“冻结”选项列表,或者在 flattenOptions 没有实际变化时避免不必要的重算。

以下是一个建议的修改,它能正确处理过滤和锁定:

  const memoFlattenOptions = useMemo(
    () => flattenOptions,
    [lockOptions, flattenOptions],
    (prev, next) => next[0] || prev[1] === next[1],
  );

Copy link
Contributor

@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 (1)
src/hooks/useOpen.ts (1)

82-91: cancelFun 返回 true 时 lock 状态未被重置。

triggerUpdate 函数中,当 cancelFun?.() 返回 true 时,整个 if 块被跳过,导致第 90 行的 setLock(false) 不被执行。此时 lock 会保持在第 79 行设置的 true 状态。

虽然当前 BaseSelect 的使用场景中,onRootBlur 中的 cancel 会紧接着被 onRootMouseDowntriggerOpen(true) 调用重置,但这种依赖于后续操作的重置方式存在风险。如果未来有其他调用者以不同的方式使用 triggerOpen(false, { cancelFun }) 但未紧跟 toggleOpen(true) 调用,lock 将长期处于 true 状态,可能影响 lockOptions 相关的 UI 更新逻辑(如 OptionList 的 memoization)。

建议在 cancel 发生时也重置 lock 状态,或在 API 层面明确文档化这一行为约束。

🧹 Nitpick comments (1)
src/OptionList.tsx (1)

70-74: 建议添加注释说明比较器逻辑。

当前的 comparator 逻辑比较隐晦:

  • next[0] && !next[1]open && !lockOptions
  • 返回 true 时更新 options,返回 false 时使用缓存

这意味着:当下拉框正在关闭时(lockOptions=true),保持 options 缓存不变,防止 UI 闪烁。建议添加注释帮助后续维护者理解这段逻辑。

建议的改进
  const memoFlattenOptions = useMemo(
    () => flattenOptions,
    [open, lockOptions],
+   // Only update options when:
+   // 1. Dropdown is open (next[0] = true)
+   // 2. Options are not locked during close transition (next[1] = false)
+   // This prevents UI flicker when closing the dropdown
    (prev, next) => next[0] && !next[1],
  );

@yoyo837
Copy link
Member

yoyo837 commented Jan 23, 2026

如果jack不在新的列表里了呢

@zombieJ
Copy link
Member Author

zombieJ commented Jan 23, 2026

如果jack不在新的列表里了呢

lock 是无论如何在一个 macro task 后都会释放的,就会更新到同步的状态

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.

4 participants