diff --git a/packages/react-reconciler/src/ReactFiberCommitWork.new.js b/packages/react-reconciler/src/ReactFiberCommitWork.new.js index 5f8de4fab94e5..600f8f5bf4a3c 100644 --- a/packages/react-reconciler/src/ReactFiberCommitWork.new.js +++ b/packages/react-reconciler/src/ReactFiberCommitWork.new.js @@ -1121,7 +1121,7 @@ function commitLayoutEffectOnFiber( if (flags & Ref) { safelyAttachRef(finishedWork, finishedWork.return); } - } else if (finishedWork.pendingProps.mode !== undefined) { + } else { safelyDetachRef(finishedWork, finishedWork.return); } } else { @@ -2148,6 +2148,8 @@ function commitDeletionEffectsOnFiber( offscreenSubtreeWasHidden = prevOffscreenSubtreeWasHidden || deletedFiber.memoizedState !== null; + safelyDetachRef(deletedFiber, nearestMountedAncestor); + recursivelyTraverseDeletionEffects( finishedRoot, nearestMountedAncestor, diff --git a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js index 6180c8a1e7105..43f5d5f9418dd 100644 --- a/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js +++ b/packages/react-reconciler/src/__tests__/ReactOffscreen-test.js @@ -1307,4 +1307,42 @@ describe('ReactOffscreen', () => { expect(offscreenRef.current).not.toBeNull(); }); }); + + // @gate enableOffscreen + it('should detach ref if Offscreen is unmounted', async () => { + let offscreenRef; + + function App({showOffscreen}) { + offscreenRef = useRef(null); + return showOffscreen ? ( + { + offscreenRef.current = ref; + }}> +
+ + ) : null; + } + + const root = ReactNoop.createRoot(); + + await act(async () => { + root.render(); + }); + + expect(offscreenRef.current).not.toBeNull(); + + await act(async () => { + root.render(); + }); + + expect(offscreenRef.current).toBeNull(); + + await act(async () => { + root.render(); + }); + + expect(offscreenRef.current).not.toBeNull(); + }); });