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();
+ });
});