Skip to content

Commit

Permalink
Add detach to Offscreen component
Browse files Browse the repository at this point in the history
  • Loading branch information
sammy-SC committed Sep 14, 2022
1 parent d8611ac commit d17ae6e
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 14 deletions.
2 changes: 2 additions & 0 deletions packages/react-reconciler/src/ReactFiber.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ export function createFiberFromOffscreen(
_pendingMarkers: null,
_retryCache: null,
_transitions: null,
detach: () => {},
};
fiber.stateNode = primaryChildInstance;
return fiber;
Expand All @@ -744,6 +745,7 @@ export function createFiberFromLegacyHidden(
_pendingMarkers: null,
_transitions: null,
_retryCache: null,
detach: () => {},
};
fiber.stateNode = instance;
return fiber;
Expand Down
2 changes: 2 additions & 0 deletions packages/react-reconciler/src/ReactFiber.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,7 @@ export function createFiberFromOffscreen(
_pendingMarkers: null,
_retryCache: null,
_transitions: null,
detach: () => {},
};
fiber.stateNode = primaryChildInstance;
return fiber;
Expand All @@ -744,6 +745,7 @@ export function createFiberFromLegacyHidden(
_pendingMarkers: null,
_transitions: null,
_retryCache: null,
detach: () => {},
};
fiber.stateNode = instance;
return fiber;
Expand Down
6 changes: 4 additions & 2 deletions packages/react-reconciler/src/ReactFiberBeginWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
enableCPUSuspense,
enableUseMutableSource,
} from 'shared/ReactFeatureFlags';

import {OffscreenDetached} from './ReactFiberOffscreenComponent';
import checkPropTypes from 'shared/checkPropTypes';
import {
markComponentRenderStarted,
Expand Down Expand Up @@ -683,7 +683,9 @@ function updateOffscreenComponent(

if (
nextProps.mode === 'hidden' ||
(enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding')
(enableLegacyHidden &&
nextProps.mode === 'unstable-defer-without-hiding') ||
workInProgress.stateNode._visibility & OffscreenDetached
) {
// Rendering a hidden tree.

Expand Down
6 changes: 4 additions & 2 deletions packages/react-reconciler/src/ReactFiberBeginWork.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import {
enableCPUSuspense,
enableUseMutableSource,
} from 'shared/ReactFeatureFlags';

import {OffscreenDetached} from './ReactFiberOffscreenComponent';
import checkPropTypes from 'shared/checkPropTypes';
import {
markComponentRenderStarted,
Expand Down Expand Up @@ -683,7 +683,9 @@ function updateOffscreenComponent(

if (
nextProps.mode === 'hidden' ||
(enableLegacyHidden && nextProps.mode === 'unstable-defer-without-hiding')
(enableLegacyHidden &&
nextProps.mode === 'unstable-defer-without-hiding') ||
workInProgress.stateNode._visibility & OffscreenDetached
) {
// Rendering a hidden tree.

Expand Down
30 changes: 28 additions & 2 deletions packages/react-reconciler/src/ReactFiberCommitWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type {
import type {HookFlags} from './ReactHookEffectTags';
import type {Cache} from './ReactFiberCacheComponent.new';
import type {RootState} from './ReactFiberRoot.new';
import {scheduleMicrotask} from './ReactFiberHostConfig';
import type {
Transition,
TracingMarkerInstance,
Expand Down Expand Up @@ -154,6 +155,7 @@ import {
setIsRunningInsertionEffect,
getExecutionContext,
CommitContext,
RenderContext,
NoContext,
} from './ReactFiberWorkLoop.new';
import {
Expand Down Expand Up @@ -182,6 +184,7 @@ import {releaseCache, retainCache} from './ReactFiberCacheComponent.new';
import {clearTransitionsForLanes} from './ReactFiberLane.new';
import {
OffscreenVisible,
OffscreenDetached,
OffscreenPassiveEffectsConnected,
} from './ReactFiberOffscreenComponent';
import {
Expand Down Expand Up @@ -1078,7 +1081,9 @@ function commitLayoutEffectOnFiber(
case OffscreenComponent: {
const isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode;
if (isModernRoot) {
const isHidden = finishedWork.memoizedState !== null;
const isHidden =
finishedWork.memoizedState !== null ||
finishedWork.stateNode._visibility & OffscreenDetached;
const newOffscreenSubtreeIsHidden =
isHidden || offscreenSubtreeIsHidden;
if (newOffscreenSubtreeIsHidden) {
Expand Down Expand Up @@ -2255,6 +2260,23 @@ function getRetryCache(finishedWork) {
}
}

function attachOffscreenActions(offscreenFiber: Fiber, root: FiberRoot) {
offscreenFiber.stateNode.detach = () => {
const executionContext = getExecutionContext();
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
scheduleMicrotask(() => {
offscreenFiber.stateNode._visibility |= OffscreenDetached;
disappearLayoutEffects(offscreenFiber);
disconnectPassiveEffect(offscreenFiber);
});
} else {
offscreenFiber.stateNode._visibility |= OffscreenDetached;
disappearLayoutEffects(offscreenFiber);
disconnectPassiveEffect(offscreenFiber);
}
};
}

function attachSuspenseRetryListeners(
finishedWork: Fiber,
wakeables: Set<Wakeable>,
Expand Down Expand Up @@ -2633,6 +2655,7 @@ function commitMutationEffectsOnFiber(
}

commitReconciliationEffects(finishedWork);
attachOffscreenActions(finishedWork, root);

if (flags & Visibility) {
const offscreenInstance: OffscreenInstance = finishedWork.stateNode;
Expand All @@ -2659,7 +2682,10 @@ function commitMutationEffectsOnFiber(
}
}

if (supportsMutation) {
if (
supportsMutation &&
!(offscreenInstance._visibility & OffscreenDetached)
) {
// TODO: This needs to run whenever there's an insertion or update
// inside a hidden Offscreen tree.
hideOrUnhideAllChildren(offscreenBoundary, isHidden);
Expand Down
30 changes: 28 additions & 2 deletions packages/react-reconciler/src/ReactFiberCommitWork.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import type {
import type {HookFlags} from './ReactHookEffectTags';
import type {Cache} from './ReactFiberCacheComponent.old';
import type {RootState} from './ReactFiberRoot.old';
import {scheduleMicrotask} from './ReactFiberHostConfig';
import type {
Transition,
TracingMarkerInstance,
Expand Down Expand Up @@ -154,6 +155,7 @@ import {
setIsRunningInsertionEffect,
getExecutionContext,
CommitContext,
RenderContext,
NoContext,
} from './ReactFiberWorkLoop.old';
import {
Expand Down Expand Up @@ -182,6 +184,7 @@ import {releaseCache, retainCache} from './ReactFiberCacheComponent.old';
import {clearTransitionsForLanes} from './ReactFiberLane.old';
import {
OffscreenVisible,
OffscreenDetached,
OffscreenPassiveEffectsConnected,
} from './ReactFiberOffscreenComponent';
import {
Expand Down Expand Up @@ -1078,7 +1081,9 @@ function commitLayoutEffectOnFiber(
case OffscreenComponent: {
const isModernRoot = (finishedWork.mode & ConcurrentMode) !== NoMode;
if (isModernRoot) {
const isHidden = finishedWork.memoizedState !== null;
const isHidden =
finishedWork.memoizedState !== null ||
finishedWork.stateNode._visibility & OffscreenDetached;
const newOffscreenSubtreeIsHidden =
isHidden || offscreenSubtreeIsHidden;
if (newOffscreenSubtreeIsHidden) {
Expand Down Expand Up @@ -2255,6 +2260,23 @@ function getRetryCache(finishedWork) {
}
}

function attachOffscreenActions(offscreenFiber: Fiber, root: FiberRoot) {
offscreenFiber.stateNode.detach = () => {
const executionContext = getExecutionContext();
if ((executionContext & (RenderContext | CommitContext)) !== NoContext) {
scheduleMicrotask(() => {
offscreenFiber.stateNode._visibility |= OffscreenDetached;
disappearLayoutEffects(offscreenFiber);
disconnectPassiveEffect(offscreenFiber);
});
} else {
offscreenFiber.stateNode._visibility |= OffscreenDetached;
disappearLayoutEffects(offscreenFiber);
disconnectPassiveEffect(offscreenFiber);
}
};
}

function attachSuspenseRetryListeners(
finishedWork: Fiber,
wakeables: Set<Wakeable>,
Expand Down Expand Up @@ -2633,6 +2655,7 @@ function commitMutationEffectsOnFiber(
}

commitReconciliationEffects(finishedWork);
attachOffscreenActions(finishedWork, root);

if (flags & Visibility) {
const offscreenInstance: OffscreenInstance = finishedWork.stateNode;
Expand All @@ -2659,7 +2682,10 @@ function commitMutationEffectsOnFiber(
}
}

if (supportsMutation) {
if (
supportsMutation &&
!(offscreenInstance._visibility & OffscreenDetached)
) {
// TODO: This needs to run whenever there's an insertion or update
// inside a hidden Offscreen tree.
hideOrUnhideAllChildren(offscreenBoundary, isHidden);
Expand Down
11 changes: 10 additions & 1 deletion packages/react-reconciler/src/ReactFiberCompleteWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type {
SuspenseListRenderState,
} from './ReactFiberSuspenseComponent.new';
import type {OffscreenState} from './ReactFiberOffscreenComponent';
import {OffscreenDetached} from './ReactFiberOffscreenComponent';
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.new';
import type {Cache} from './ReactFiberCacheComponent.new';
import {
Expand Down Expand Up @@ -410,7 +411,15 @@ if (supportsMutation) {
if (child !== null) {
child.return = node;
}
appendAllChildrenToContainer(containerChildSet, node, true, true);
// Detached tree is hidden from user space.
const _needsVisibilityToggle =
node.stateNode._visibility & OffscreenDetached === 0;
appendAllChildrenToContainer(
containerChildSet,
node,
_needsVisibilityToggle,
true,
);
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
Expand Down
11 changes: 10 additions & 1 deletion packages/react-reconciler/src/ReactFiberCompleteWork.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type {
SuspenseListRenderState,
} from './ReactFiberSuspenseComponent.old';
import type {OffscreenState} from './ReactFiberOffscreenComponent';
import {OffscreenDetached} from './ReactFiberOffscreenComponent';
import type {TracingMarkerInstance} from './ReactFiberTracingMarkerComponent.old';
import type {Cache} from './ReactFiberCacheComponent.old';
import {
Expand Down Expand Up @@ -410,7 +411,15 @@ if (supportsMutation) {
if (child !== null) {
child.return = node;
}
appendAllChildrenToContainer(containerChildSet, node, true, true);
// Detached tree is hidden from user space.
const _needsVisibilityToggle =
node.stateNode._visibility & OffscreenDetached === 0;
appendAllChildrenToContainer(
containerChildSet,
node,
_needsVisibilityToggle,
true,
);
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
Expand Down
6 changes: 4 additions & 2 deletions packages/react-reconciler/src/ReactFiberOffscreenComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,14 @@ export type OffscreenQueue = {

type OffscreenVisibility = number;

export const OffscreenVisible = /* */ 0b01;
export const OffscreenPassiveEffectsConnected = /* */ 0b10;
export const OffscreenVisible = /* */ 0b001;
export const OffscreenDetached = /* */ 0b010;
export const OffscreenPassiveEffectsConnected = /* */ 0b100;

export type OffscreenInstance = {
_visibility: OffscreenVisibility,
_pendingMarkers: Set<TracingMarkerInstance> | null,
_transitions: Set<Transition> | null,
_retryCache: WeakSet<Wakeable> | Set<Wakeable> | null,
detach: () => void,
};
2 changes: 1 addition & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ type ExecutionContext = number;

export const NoContext = /* */ 0b000;
const BatchedContext = /* */ 0b001;
const RenderContext = /* */ 0b010;
export const RenderContext = /* */ 0b010;
export const CommitContext = /* */ 0b100;

type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6;
Expand Down
2 changes: 1 addition & 1 deletion packages/react-reconciler/src/ReactFiberWorkLoop.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ type ExecutionContext = number;

export const NoContext = /* */ 0b000;
const BatchedContext = /* */ 0b001;
const RenderContext = /* */ 0b010;
export const RenderContext = /* */ 0b010;
export const CommitContext = /* */ 0b100;

type RootExitStatus = 0 | 1 | 2 | 3 | 4 | 5 | 6;
Expand Down
Loading

0 comments on commit d17ae6e

Please sign in to comment.