Skip to content

feat(think, thought-chain): support destroyOnHidden - #1985

Merged
kimteayon merged 1 commit into
ant-design:mainfrom
wryyyds7:reproduce/issue-1954-destroyOnHidden
Jul 21, 2026
Merged

feat(think, thought-chain): support destroyOnHidden#1985
kimteayon merged 1 commit into
ant-design:mainfrom
wryyyds7:reproduce/issue-1954-destroyOnHidden

Conversation

@wryyyds7

@wryyyds7 wryyyds7 commented Jul 17, 2026

Copy link
Copy Markdown

Description

Closes #1954

Add destroyOnHidden prop to Think and ThoughtChain components, allowing users to control whether content DOM nodes are removed from the DOM when the component is collapsed.

Background

Current state

After investigating the source code, we found that the original code does not explicitly set removeOnLeave on CSSMotion. Since CSSMotion's removeOnLeave defaults to true, content DOM nodes are already being removed when collapsed. This means the "DOM not destroyed" behavior described in the issue may have already been resolved in the current version.

This PR is a minor enhancement suggestion: expose CSSMotion's removeOnLeave as a user-facing destroyOnHidden prop so that users can explicitly opt into either behavior:

  • destroyOnHidden=true (default): content node is removed from DOM after collapse animation — current behavior, no breaking change
  • destroyOnHidden=false: content node is kept in DOM with leavedClassName for CSS-only hiding — useful for streaming rendering scenarios (support destroyOnHidden with Think and ThoughtChain #1677) where preserving DOM state is preferred

Changes

Think (packages/x/components/think/)

  • ThinkProps: added destroyOnHidden?: boolean prop (default: true)
  • Think.tsx: passes destroyOnHidden to CSSMotion's removeOnLeave

ThoughtChain (packages/x/components/thought-chain/)

  • ThoughtChainItemType: added destroyOnHidden?: boolean prop (default: true)
  • Node.tsx: passes destroyOnHidden to CSSMotion's removeOnLeave

Demo

  • think/demo/destroyOnHidden.tsx — demo with toggle switch
  • thought-chain/demo/destroyOnHidden.tsx — demo with toggle switch

Unit Tests

  • Think: test that content is removed from DOM when destroyOnHidden=true, and kept when destroyOnHidden=false
  • ThoughtChain: same assertions for collapsible items

Docs

  • Updated index.zh-CN.md and index.en-US.md for both components

Checklist

  • Demo added
  • Unit tests added (assert DOM not present when hidden)
  • Documentation updated
  • No breaking changes (default value preserves current behavior)

Add  prop to Think and ThoughtChain components,
passing it to CSSMotion's  to control whether content
DOM nodes are removed when collapsed.

- Think: new  prop (default: true)
- ThoughtChain: new  on ThoughtChainItemType (default: true)
- Add demo for both components
- Add unit tests for both components
- Update API docs (zh-CN & en-US)

Closes ant-design#1954
@dosubot dosubot Bot added documentation Improvements or additions to documentation enhancement New feature or request javascript Pull requests that update Javascript code labels Jul 17, 2026
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

为 Think 和 ThoughtChain 增加 destroyOnHidden,控制折叠内容是否从 DOM 移除,并补充测试、示例及中英文文档。

Changes

Think 与 ThoughtChain 隐藏销毁控制

Layer / File(s) Summary
Think 销毁策略与验证
packages/x/components/think/Think.tsx, packages/x/components/think/__tests__/*, packages/x/components/think/demo/*, packages/x/components/think/index.*.md
Think 新增默认值为 truedestroyOnHidden 属性,并通过 CSSMotion.removeOnLeave 控制隐藏内容是否移除;测试、示例和 API 文档同步更新。
ThoughtChain 节点销毁策略与验证
packages/x/components/thought-chain/interface.ts, packages/x/components/thought-chain/Node.tsx, packages/x/components/thought-chain/__tests__/*, packages/x/components/thought-chain/demo/*, packages/x/components/thought-chain/index.*.md
ThoughtChain 节点新增 destroyOnHidden 配置,并将其传递给 CSSMotion;测试、示例和 API 文档覆盖该行为。

Estimated code review effort: 2 (Simple) | ~10 minutes

Suggested reviewers: div627

Poem

兔耳一竖,折叠开关亮,
内容藏起,DOM 轻轻忙。
Think 和链路步调齐,
测试文档都添新装,
咕咕庆祝改动香!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 实现覆盖了 #1954 要求的属性支持、demo、单测和文档更新,符合验收目标。
Out of Scope Changes check ✅ Passed 变更集中在 Think 与 ThoughtChain 的 destroyOnHidden 支持及其配套说明,没有明显无关改动。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了在 Think 和 ThoughtChain 中新增 destroyOnHidden 支持这一主要变更。
✨ 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.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

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 introduces a new destroyOnHidden prop (defaulting to true) to both the Think and ThoughtChain components, allowing users to control whether the content node is destroyed from the DOM when collapsed. It also includes corresponding documentation, demos, and unit tests. A review comment identifies a potential false positive in the ThoughtChain unit tests, where fake timers need to be advanced using jest.runAllTimers() to ensure the collapse transition completes before asserting on the DOM state.

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.

Comment on lines +259 to +296
it('should keep content in DOM when destroyOnHidden is false and collapsed', () => {
const { container, rerender } = render(
<ThoughtChain
items={[
{
key: 'keep-test',
title: 'Collapsible',
content: 'Kept content',
collapsible: true,
destroyOnHidden: false,
},
]}
expandedKeys={['keep-test']}
/>,
);

// Expanded, content should exist
expect(container.querySelector('.ant-thought-chain-node-content')).toBeTruthy();

// Collapse
rerender(
<ThoughtChain
items={[
{
key: 'keep-test',
title: 'Collapsible',
content: 'Kept content',
collapsible: true,
destroyOnHidden: false,
},
]}
expandedKeys={[]}
/>,
);

// Collapsed with destroyOnHidden=false, content node should still exist
expect(container.querySelector('.ant-thought-chain-node-content')).toBeTruthy();
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Without advancing the fake timers (e.g., using jest.runAllTimers()), the collapse transition does not complete. As a result, the DOM node remains in the DOM immediately after rerender regardless of whether destroyOnHidden is true or false. This makes the test a false positive because it would pass even if destroyOnHidden was broken or ignored. Advancing the timers ensures we are asserting on the final state after the transition completes.

  it('should keep content in DOM when destroyOnHidden is false and collapsed', () => {
    const { container, rerender } = render(
      <ThoughtChain
        items={[
          {
            key: 'keep-test',
            title: 'Collapsible',
            content: 'Kept content',
            collapsible: true,
            destroyOnHidden: false,
          },
        ]}
        expandedKeys={['keep-test']}
      />,
    );

    // Expanded, content should exist
    expect(container.querySelector('.ant-thought-chain-node-content')).toBeTruthy();

    // Collapse
    rerender(
      <ThoughtChain
        items={[
          {
            key: 'keep-test',
            title: 'Collapsible',
            content: 'Kept content',
            collapsible: true,
            destroyOnHidden: false,
          },
        ]}
        expandedKeys={[]}
      />,
    );

    // Advance timers to let the transition finish
    jest.runAllTimers();

    // Collapsed with destroyOnHidden=false, content node should still exist
    expect(container.querySelector('.ant-thought-chain-node-content')).toBeTruthy();
  });

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@packages/x/components/think/__tests__/index.test.tsx`:
- Around line 95-107: Extend the destroyOnHidden test at
packages/x/components/think/__tests__/index.test.tsx:95-107 by collapsing Think
after the expansion assertion, waiting with waitFakeTimer, and asserting
.ant-think-content is removed. Update
packages/x/components/thought-chain/__tests__/index.test.tsx:239-257 to render
expanded via expandedKeys, assert content exists, then rerender without that
key, wait for any exit animation, and assert the content is removed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9fc26a7b-b578-4a41-88ff-f1fe15714f8a

📥 Commits

Reviewing files that changed from the base of the PR and between 17db20b and 4f9a023.

📒 Files selected for processing (13)
  • packages/x/components/think/Think.tsx
  • packages/x/components/think/__tests__/index.test.tsx
  • packages/x/components/think/demo/destroyOnHidden.md
  • packages/x/components/think/demo/destroyOnHidden.tsx
  • packages/x/components/think/index.en-US.md
  • packages/x/components/think/index.zh-CN.md
  • packages/x/components/thought-chain/Node.tsx
  • packages/x/components/thought-chain/__tests__/index.test.tsx
  • packages/x/components/thought-chain/demo/destroyOnHidden.md
  • packages/x/components/thought-chain/demo/destroyOnHidden.tsx
  • packages/x/components/thought-chain/index.en-US.md
  • packages/x/components/thought-chain/index.zh-CN.md
  • packages/x/components/thought-chain/interface.ts

Comment on lines +95 to +107
it('Think should remove content from DOM when destroyOnHidden is true and collapsed', async () => {
const { container } = render(
<Think title="test" destroyOnHidden defaultExpanded={false}>
content
</Think>,
);
// collapsed by default, content should not be in DOM
expect(container.querySelector('.ant-think-content')).toBeNull();
// expand
fireEvent.click(container.querySelector('.ant-think-status-wrapper')!);
await waitFakeTimer();
expect(container.querySelector('.ant-think-content')).toBeTruthy();
});

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

完善对折叠卸载过程的测试用例覆盖。

这两个针对 destroyOnHidden={true} 的测试用例虽然旨在验证“折叠时从 DOM 移除”,但实际上仅校验了初始渲染且默认处于折叠状态时节点不存在的情况。为了确保卸载功能完全符合预期,建议先触发展开使内容挂载到 DOM 中,然后再触发折叠,最后断言节点已被成功卸载移除。

  • packages/x/components/think/__tests__/index.test.tsx#L95-L107: 建议在现有断言后,补充触发折叠的代码(例如点击事件及 await waitFakeTimer();),并断言内容节点重新变为 null
  • packages/x/components/thought-chain/__tests__/index.test.tsx#L239-L257: 建议初始渲染时指定 expandedKeys 使其处于展开状态,断言节点存在后,通过 rerender 移除该 key 触发折叠(注意如涉及离场动画需作相应等待),最后再断言内容节点不再存在。
📍 Affects 2 files
  • packages/x/components/think/__tests__/index.test.tsx#L95-L107 (this comment)
  • packages/x/components/thought-chain/__tests__/index.test.tsx#L239-L257
🤖 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 `@packages/x/components/think/__tests__/index.test.tsx` around lines 95 - 107,
Extend the destroyOnHidden test at
packages/x/components/think/__tests__/index.test.tsx:95-107 by collapsing Think
after the expansion assertion, waiting with waitFakeTimer, and asserting
.ant-think-content is removed. Update
packages/x/components/thought-chain/__tests__/index.test.tsx:239-257 to render
expanded via expandedKeys, assert content exists, then rerender without that
key, wait for any exit animation, and assert the content is removed.

@wryyyds7

Copy link
Copy Markdown
Author

#1954

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 21, 2026
@kimteayon
kimteayon merged commit 818b6e0 into ant-design:main Jul 21, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request javascript Pull requests that update Javascript code lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Good First Issue] Think / ThoughtChain 支持 destroyOnHidden

2 participants