Skip to content

fix: destroyOnHidden should work when forceRender is true - #581

Open
EmilyyyLiu wants to merge 4 commits into
react-component:masterfrom
EmilyyyLiu:fix/destroyOnHidden-with-forceRender
Open

fix: destroyOnHidden should work when forceRender is true#581
EmilyyyLiu wants to merge 4 commits into
react-component:masterfrom
EmilyyyLiu:fix/destroyOnHidden-with-forceRender

Conversation

@EmilyyyLiu

@EmilyyyLiu EmilyyyLiu commented Jul 20, 2026

Copy link
Copy Markdown
Contributor

Description

修复 forceRender 在 时destroyOnHidden不生效的问题。

Problem

当同时设置 和 时,隐藏对话框后内容不会被销毁,这与预期行为不符。

Solution

修改判断逻辑,使用 来检查组件是否曾经打开过,而不是依赖 和 的组合条件。

关联issue

ant-design/ant-design#28847

Changes

  • : 调整 的判断条件
  • : 添加测试用例

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug 修复

    • 优化对话框隐藏时内容的卸载逻辑,确保在启用“隐藏时销毁”后,内容仅在对话框实际打开过并再次隐藏时被移除。
    • 改善同时启用“强制渲染”和“隐藏时销毁”时的行为:内容会先正常渲染,并在再次隐藏后正确卸载。
  • 测试

    • 增加相关场景测试,验证内容在初始隐藏、显示及再次隐藏阶段的正确状态。

- Fix logic to use animatedVisible to check if component has ever been opened
- Add test case for forceRender + destroyOnHidden scenario

Co-Authored-By: Claude <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 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 Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@EmilyyyLiu, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 3 seconds

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c9750757-93f0-4885-91fe-bcc8331f7110

📥 Commits

Reviewing files that changed from the base of the PR and between 349ea90 and b23af5b.

📒 Files selected for processing (1)
  • src/DialogWrap.tsx

Walkthrough

调整 DialogWrap 的隐藏销毁判定,使 forceRender 初始渲染仍然生效,并在组件曾打开后隐藏时销毁内容;新增对应测试覆盖该行为。

Changes

对话框隐藏销毁

Layer / File(s) Summary
隐藏销毁条件与测试
src/DialogWrap.tsx, tests/index.spec.tsx
销毁判定改为依据 animatedVisible 与当前 visible 状态执行;新增测试验证 forceRenderdestroyOnHidden 同时启用时,组件关闭后会卸载子内容。

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

Possibly related PRs

Suggested reviewers: afc163

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 标题准确概括了此次修复的核心:在 forceRender 为 true 时,destroyOnHidden 仍应按预期生效。
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.
✨ 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 modifies the destruction logic in DialogWrap to ensure the component is destroyed when destroyOnHidden is true, even if forceRender is enabled, and adds a corresponding test. However, the reviewer identified a critical regression where the new condition causes the dialog to unmount immediately when visible becomes false, which skips close animations and prevents afterClose from being called. A solution using a ref to track whether the dialog has ever been opened was suggested to resolve this issue.

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 thread src/DialogWrap.tsx Outdated
@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.95%. Comparing base (b2b9d12) to head (b23af5b).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #581      +/-   ##
==========================================
+ Coverage   98.94%   98.95%   +0.01%     
==========================================
  Files           8        8              
  Lines         190      192       +2     
  Branches       69       69              
==========================================
+ Hits          188      190       +2     
  Misses          2        2              

☔ View full report in Codecov by Harness.
📢 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.

- Use hasOpenedRef to track if dialog has ever been opened
- Wait for afterClose callback before destroying (preserves animation)
- Fixes regression where dialog would unmount immediately without animation

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/index.spec.tsx (1)

180-186: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

增加对卸载时机(动画期间)的断言。

为了防止上述立即卸载的 Bug 再次出现,建议在触发 visible={false} 之后、动画计时器运行之前,验证 DOM 元素尚未被卸载。这样能真正测试组件是否在等待动画结束(afterClose)后才执行销毁操作。

♻️ 建议的重构
       // Hide - should destroy because destroyOnHidden is true
       rerender(<Demo visible={false} />);
+      
+      // 验证在动画结束前,元素仍存在于 DOM 中
+      expect(document.querySelectorAll('.test-force-destroy')).toHaveLength(1);
+
       act(() => {
         jest.runAllTimers();
       });
       expect(document.querySelectorAll('.test-force-destroy')).toHaveLength(0);
     });
🤖 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/index.spec.tsx` around lines 180 - 186, Update the destroyOnHidden test
around the visible=false rerender to assert that .test-force-destroy is still
present before jest.runAllTimers executes, then retain the existing assertion
that it is removed after timers complete, verifying destruction occurs only
after the close animation finishes.
🤖 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 `@src/DialogWrap.tsx`:
- Around line 50-54: Update the destroy-on-hidden condition in DialogWrap to
check !animatedVisible instead of !visible, while retaining destroyOnHidden and
hasOpenedRef.current. This must keep the Dialog mounted during the closing
animation and only return null after animatedVisible becomes false following
afterClose.

---

Nitpick comments:
In `@tests/index.spec.tsx`:
- Around line 180-186: Update the destroyOnHidden test around the visible=false
rerender to assert that .test-force-destroy is still present before
jest.runAllTimers executes, then retain the existing assertion that it is
removed after timers complete, verifying destruction occurs only after the close
animation finishes.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 682cced5-37b2-4761-8b04-cb5011c03ac9

📥 Commits

Reviewing files that changed from the base of the PR and between b2b9d12 and 28ecb13.

📒 Files selected for processing (2)
  • src/DialogWrap.tsx
  • tests/index.spec.tsx

Comment thread src/DialogWrap.tsx
刘欢 added 2 commits July 20, 2026 16:58
- Add !animatedVisible to condition to ensure exit animation plays
- afterClose callback will be called before destroying component
- Use hasOpenedRef initialized with visible prop to track opened state
- Add !animatedVisible to wait for animation before destroy
- Fixes exit animation being interrupted
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.

1 participant