Skip to content

fix(conversations): avoid rerendering all items on selection - #2036

Open
advance-hub wants to merge 2 commits into
ant-design:mainfrom
advance-hub:codex/fix-conversations-selection-performance
Open

fix(conversations): avoid rerendering all items on selection#2036
advance-hub wants to merge 2 commits into
ant-design:mainfrom
advance-hub:codex/fix-conversations-selection-performance

Conversation

@advance-hub

@advance-hub advance-hub commented Aug 25, 2026

Copy link
Copy Markdown

Fixes #1871

Background

Changing the active conversation caused every item in a large list to rerender. The parent recomputed merged styles, resolved the menu callback for every row, and passed a new click callback on each selection change. With 500 items, a single click performed work proportional to the full list.

Changes

  • Memoize individual conversation items so unchanged rows can skip selection updates.
  • Keep the item click callback stable with useEvent.
  • Move menu resolution and style merging into the item while preserving the existing style precedence.
  • Add a 500-item regression test that asserts selection work remains constant instead of scaling with the list size.

Performance evidence

Measured in the same React development build and browser session:

  • Before: 1,000 item computations per selection; 79–104 ms click-to-paint.
  • After: 3–4 item computations per selection; 21–44 ms click-to-paint.

The timing is environment-dependent; the item-computation reduction is deterministic. React development mode invokes render work more than once, which is why two affected rows can report 3–4 computations.

Recordings

Before — 1,000 item computations

Before: selection recomputes all 500 items

Open the original MP4

After — 3–4 item computations

After: selection only recomputes affected items

Open the original MP4

Verification

  • NODE_OPTIONS=--max-old-space-size=768 ../../node_modules/.bin/jest --config .jest.js components/conversations/__tests__/index.test.tsx --runInBand --no-cache (24 tests, 2 snapshots)
  • NODE_OPTIONS=--max-old-space-size=1024 ./node_modules/.bin/tsc --noEmit -p packages/x/tsconfig.json
  • ./node_modules/.bin/biome check packages/x/components/conversations/index.tsx packages/x/components/conversations/Item.tsx packages/x/components/conversations/__tests__/index.test.tsx

Summary by CodeRabbit

  • 新功能

    • 会话菜单支持根据当前会话动态生成。
    • 会话列表项新增组件样式和语义样式配置能力。
    • 新增可复用的会话菜单类型定义。
  • 性能优化

    • 优化会话列表更新机制,切换活动会话时减少不必要的菜单重新计算,提升大规模列表的响应性能。

将菜单解析与样式合并下沉到单个会话项,并稳定选中回调与语义样式属性,使 React.memo 只重渲染前后两个受影响项。

新增 500 项会话列表回归测试,保证切换选中项时计算量保持常数级。
@dosubot dosubot Bot added the enhancement New feature or request label Aug 25, 2026
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • packages/x/components/suggestion/__tests__/__snapshots__/demo.test.ts.snap is excluded by !**/*.snap

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 58a32210-646b-4c6b-bec2-3860bdb0e690

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bba65c48-36bc-4bba-a3d7-0a695ec3bb9c

📥 Commits

Reviewing files that changed from the base of the PR and between 25aad7b and f18e99c.

📒 Files selected for processing (3)
  • packages/x/components/conversations/Item.tsx
  • packages/x/components/conversations/__tests__/index.test.tsx
  • packages/x/components/conversations/index.tsx

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

Changes

会话条目现在支持独立的 ConversationsItemMenu 类型、按会话生成菜单,以及 componentStylesemanticStyle。列表组件透传这些配置,使用 React.memouseEvent,并新增 500 条目切换性能测试。

会话条目菜单与样式渲染

Layer / File(s) Summary
菜单类型、动态解析与样式合并
packages/x/components/conversations/Item.tsx
新增 ConversationsItemMenu 类型。menu 支持函数形式。条目合并 componentStylesemanticStylestyle。默认导出使用 React.memo

会话列表集成与性能验证

Layer / File(s) Summary
列表配置透传与活动项切换
packages/x/components/conversations/index.tsx, packages/x/components/conversations/__tests__/index.test.tsx
列表组件使用独立菜单类型,透传动态菜单和分层样式,并使用 useEvent 包装点击回调。测试验证 500 个条目切换活动项时菜单回调不会遍历执行。

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to f18e9

This change localizes conversation-item updates to improve selection performance while preserving existing behavior, with regression tests and standard checks completed; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant Conversations
  participant ConversationsItem
  participant MenuFunction
  Conversations->>ConversationsItem: 传入会话信息和 menu
  ConversationsItem->>MenuFunction: 按会话信息解析 menu
  MenuFunction-->>ConversationsItem: 返回菜单配置
  ConversationsItem-->>Conversations: 渲染活动状态和菜单
Loading

Suggested reviewers: kimteayon

Poem

小兔捧来新菜单,
会话逐项快切换。
五百条目不乱跑,
样式层层合得巧。
memo 守住每一项,
代码轻快月光亮。

🚥 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 标题准确概括了会话选择时避免所有条目重新渲染这一主要变更,表达简洁且具体。
Linked Issues check ✅ Passed PR 实现了 Issue #1871 的核心目标:通过 React.memo、稳定的 useEvent 回调以及条目级菜单解析,避免切换活动会话时重新计算所有条目。新增的 500 条目回归测试也验证了计算次数保持常量级。
Out of Scope Changes check ✅ Passed 代码变更均服务于 Issue #1871 的性能修复,包括条目 memo 化、回调稳定化、菜单和样式处理调整,以及性能回归测试。未发现与目标无关的代码变更。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 3…
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 3 files.

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

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.

@codecov

codecov Bot commented Aug 25, 2026

Copy link
Copy Markdown

Bundle Report

Changes will decrease total bundle size by 1.21MB (-20.74%) ⬇️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
x-markdown-array-push 1.37MB -241.69kB (-15.03%) ⬇️
antdx-array-push 1.14MB -968.61kB (-45.91%) ⬇️

Affected Assets, Files, and Routes:

view changes for bundle: x-markdown-array-push

Assets Changed:

Asset Name Size Change Total Size Change (%)
latex.min.js (New) 265.05kB 265.05kB 100.0% 🚀
latex.min.css (New) 24.39kB 24.39kB 100.0% 🚀
latex.js (Deleted) -506.75kB 0 bytes -100.0% 🗑️
latex.css (Deleted) -24.39kB 0 bytes -100.0% 🗑️
view changes for bundle: antdx-array-push

Assets Changed:

Asset Name Size Change Total Size Change (%)
antdx.min.js -968.61kB 1.14MB -45.91%

当前 CI 已被 GitHub Actions 强制切换到 Node 24,Suggestion 触发器的 SSR 输出不再为可见占位元素生成冗余的 visibility 内联样式。本提交仅校正一行快照基线,不改变组件运行时代码。

**验证说明**

1. Suggestion demo 快照测试通过。
2. Conversations 回归测试通过。
3. 合计 29 个测试、6 个快照全部通过。

@nrps9909 nrps9909 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.

Reviewed exact head f8a25ea against base 25aad7b.

The optimization preserves prop precedence while moving menu resolution and style merging into the memoized item. The parent now supplies stable item data and a useEvent-backed click handler, so an active-key change invalidates the old and new active rows instead of every row. Changed menu, style, className, item data, direction, or active props still invalidate the relevant memoized item through normal shallow comparison.

Validation performed:

  • Removed React.memo locally while retaining the rest of the PR: the 500-item regression failed with 2,000 post-selection menu computations, confirming the test detects the eliminated O(n) work.
  • Exact head regression stays within its constant bound and activates the selected row.
  • A temporary rerender probe kept the item array stable, replaced onActiveChange, and confirmed a memo-skipped item invokes only the newest callback through useEvent rather than a stale closure.
  • Complete Conversations scope: 24/24 tests and 2/2 snapshots passed.
  • The separately synchronized Suggestion demo scope passes 5/5 tests and 4/4 snapshots with the current dependency/runtime output.
  • packages/x TypeScript noEmit passed; Biome passed all three source/test files; git diff --check passed.
  • Live PR head still matches the tested SHA; the currently reported remote checks are green.

AI assistance disclosure: Codex was used to inspect the exact prop and memo boundaries, run the counterfactual performance and latest-callback probes, execute focused/static checks, and draft this review. I verified the reported commands and outcomes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

conversations组件items过多时(超过100),点击切换卡顿

2 participants