Skip to content

Commit

Permalink
Re-add old Fabric Offscreen impl behind flag
Browse files Browse the repository at this point in the history
There's a chance that #21960 will affect layout in a way that we don't
expect, so I'm adding back the old implementation so we can toggle the
feature with a flag.

The flag should read from the ReactNativeFeatureFlags shim so that we
can change it at runtime. I'll do that separately.
  • Loading branch information
acdlite committed Aug 3, 2021
1 parent 8a37b0e commit 2fb2dbb
Show file tree
Hide file tree
Showing 20 changed files with 259 additions and 36 deletions.
26 changes: 26 additions & 0 deletions packages/react-native-renderer/src/ReactFabricHostConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,32 @@ export function getOffscreenContainerProps(
}
}

export function cloneHiddenInstance(
instance: Instance,
type: string,
props: Props,
internalInstanceHandle: Object,
): Instance {
const viewConfig = instance.canonical.viewConfig;
const node = instance.node;
const updatePayload = create(
{style: {display: 'none'}},
viewConfig.validAttributes,
);
return {
node: cloneNodeWithNewProps(node, updatePayload),
canonical: instance.canonical,
};
}

export function cloneHiddenTextInstance(
instance: Instance,
text: string,
internalInstanceHandle: Object,
): TextInstance {
throw new Error('Not yet implemented.');
}

export function createContainerChildSet(container: Container): ChildSet {
return createChildNodeSet(container);
}
Expand Down
48 changes: 48 additions & 0 deletions packages/react-noop-renderer/src/createReactNoop.js
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,54 @@ function createReactNoop(reconciler: Function, useMutation: boolean) {
children,
};
},

cloneHiddenInstance(
instance: Instance,
type: string,
props: Props,
internalInstanceHandle: Object,
): Instance {
const clone = cloneInstance(
instance,
null,
type,
props,
props,
internalInstanceHandle,
true,
null,
);
clone.hidden = true;
return clone;
},

cloneHiddenTextInstance(
instance: TextInstance,
text: string,
internalInstanceHandle: Object,
): TextInstance {
const clone = {
text: instance.text,
id: instance.id,
parent: instance.parent,
hidden: true,
context: instance.context,
};
// Hide from unit tests
Object.defineProperty(clone, 'id', {
value: clone.id,
enumerable: false,
});
Object.defineProperty(clone, 'parent', {
value: clone.parent,
enumerable: false,
});
Object.defineProperty(clone, 'context', {
value: clone.context,
enumerable: false,
});
return clone;
},
};

const NoopRenderer = reconciler(hostConfig);
Expand Down
12 changes: 5 additions & 7 deletions packages/react-reconciler/src/ReactFiberBeginWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import {
enableLazyContextPropagation,
enableSuspenseLayoutEffectSemantics,
enableSchedulingProfiler,
enablePersistentOffscreenHostContainer,
} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';
import isArray from 'shared/isArray';
Expand Down Expand Up @@ -146,7 +147,6 @@ import {
registerSuspenseInstanceRetry,
supportsHydration,
isPrimaryRenderer,
supportsMutation,
supportsPersistence,
getOffscreenContainerProps,
} from './ReactFiberHostConfig';
Expand Down Expand Up @@ -744,7 +744,7 @@ function updateOffscreenComponent(
workInProgress.updateQueue = spawnedCachePool;
}

if (supportsPersistence) {
if (enablePersistentOffscreenHostContainer && supportsPersistence) {
// In persistent mode, the offscreen children are wrapped in a host node.
// TODO: Optimize this to use the OffscreenComponent fiber instead of
// an extra HostComponent fiber. Need to make sure this doesn't break Fabric
Expand All @@ -760,12 +760,10 @@ function updateOffscreenComponent(
renderLanes,
);
return offscreenContainer;
}
if (supportsMutation) {
} else {
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
return null;
}

function reconcileOffscreenHostContainer(
Expand Down Expand Up @@ -2383,7 +2381,7 @@ function updateSuspenseFallbackChildren(
currentPrimaryChildFragment.treeBaseDuration;
}

if (supportsPersistence) {
if (enablePersistentOffscreenHostContainer && supportsPersistence) {
// In persistent mode, the offscreen children are wrapped in a host node.
// We need to complete it now, because we're going to skip over its normal
// complete phase and go straight to rendering the fallback.
Expand Down Expand Up @@ -2411,7 +2409,7 @@ function updateSuspenseFallbackChildren(
primaryChildProps,
);

if (supportsPersistence) {
if (enablePersistentOffscreenHostContainer && supportsPersistence) {
// In persistent mode, the offscreen children are wrapped in a host node.
// We need to complete it now, because we're going to skip over its normal
// complete phase and go straight to rendering the fallback.
Expand Down
12 changes: 5 additions & 7 deletions packages/react-reconciler/src/ReactFiberBeginWork.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ import {
enableLazyContextPropagation,
enableSuspenseLayoutEffectSemantics,
enableSchedulingProfiler,
enablePersistentOffscreenHostContainer,
} from 'shared/ReactFeatureFlags';
import invariant from 'shared/invariant';
import isArray from 'shared/isArray';
Expand Down Expand Up @@ -146,7 +147,6 @@ import {
registerSuspenseInstanceRetry,
supportsHydration,
isPrimaryRenderer,
supportsMutation,
supportsPersistence,
getOffscreenContainerProps,
} from './ReactFiberHostConfig';
Expand Down Expand Up @@ -744,7 +744,7 @@ function updateOffscreenComponent(
workInProgress.updateQueue = spawnedCachePool;
}

if (supportsPersistence) {
if (enablePersistentOffscreenHostContainer && supportsPersistence) {
// In persistent mode, the offscreen children are wrapped in a host node.
// TODO: Optimize this to use the OffscreenComponent fiber instead of
// an extra HostComponent fiber. Need to make sure this doesn't break Fabric
Expand All @@ -760,12 +760,10 @@ function updateOffscreenComponent(
renderLanes,
);
return offscreenContainer;
}
if (supportsMutation) {
} else {
reconcileChildren(current, workInProgress, nextChildren, renderLanes);
return workInProgress.child;
}
return null;
}

function reconcileOffscreenHostContainer(
Expand Down Expand Up @@ -2383,7 +2381,7 @@ function updateSuspenseFallbackChildren(
currentPrimaryChildFragment.treeBaseDuration;
}

if (supportsPersistence) {
if (enablePersistentOffscreenHostContainer && supportsPersistence) {
// In persistent mode, the offscreen children are wrapped in a host node.
// We need to complete it now, because we're going to skip over its normal
// complete phase and go straight to rendering the fallback.
Expand Down Expand Up @@ -2411,7 +2409,7 @@ function updateSuspenseFallbackChildren(
primaryChildProps,
);

if (supportsPersistence) {
if (enablePersistentOffscreenHostContainer && supportsPersistence) {
// In persistent mode, the offscreen children are wrapped in a host node.
// We need to complete it now, because we're going to skip over its normal
// complete phase and go straight to rendering the fallback.
Expand Down
87 changes: 77 additions & 10 deletions packages/react-reconciler/src/ReactFiberCompleteWork.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ import {
supportsMutation,
supportsPersistence,
cloneInstance,
cloneHiddenInstance,
cloneHiddenTextInstance,
createContainerChildSet,
appendChildToContainerChildSet,
finalizeContainerChildren,
Expand Down Expand Up @@ -128,6 +130,7 @@ import {
enableProfilerTimer,
enableCache,
enableSuspenseLayoutEffectSemantics,
enablePersistentOffscreenHostContainer,
} from 'shared/ReactFeatureFlags';
import {
renderDidSuspend,
Expand Down Expand Up @@ -198,7 +201,12 @@ let updateHostText;
if (supportsMutation) {
// Mutation mode

appendAllChildren = function(parent: Instance, workInProgress: Fiber) {
appendAllChildren = function(
parent: Instance,
workInProgress: Fiber,
needsVisibilityToggle: boolean,
isHidden: boolean,
) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
let node = workInProgress.child;
Expand Down Expand Up @@ -286,22 +294,53 @@ if (supportsMutation) {
} else if (supportsPersistence) {
// Persistent host tree mode

appendAllChildren = function(parent: Instance, workInProgress: Fiber) {
appendAllChildren = function(
parent: Instance,
workInProgress: Fiber,
needsVisibilityToggle: boolean,
isHidden: boolean,
) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
let node = workInProgress.child;
while (node !== null) {
// eslint-disable-next-line no-labels
branches: if (node.tag === HostComponent) {
const instance = node.stateNode;
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const props = node.memoizedProps;
const type = node.type;
instance = cloneHiddenInstance(instance, type, props, node);
}
appendInitialChild(parent, instance);
} else if (node.tag === HostText) {
const instance = node.stateNode;
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const text = node.memoizedProps;
instance = cloneHiddenTextInstance(instance, text, node);
}
appendInitialChild(parent, instance);
} else if (node.tag === HostPortal) {
// If we have a portal child, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
) {
// The children in this boundary are hidden. Toggle their visibility
// before appending.
const child = node.child;
if (child !== null) {
child.return = node;
}
if (enablePersistentOffscreenHostContainer) {
appendAllChildren(parent, node, false, false);
} else {
appendAllChildren(parent, node, true, true);
}
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
Expand All @@ -327,22 +366,50 @@ if (supportsMutation) {
const appendAllChildrenToContainer = function(
containerChildSet: ChildSet,
workInProgress: Fiber,
needsVisibilityToggle: boolean,
isHidden: boolean,
) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
let node = workInProgress.child;
while (node !== null) {
// eslint-disable-next-line no-labels
branches: if (node.tag === HostComponent) {
const instance = node.stateNode;
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const props = node.memoizedProps;
const type = node.type;
instance = cloneHiddenInstance(instance, type, props, node);
}
appendChildToContainerChildSet(containerChildSet, instance);
} else if (node.tag === HostText) {
const instance = node.stateNode;
let instance = node.stateNode;
if (needsVisibilityToggle && isHidden) {
// This child is inside a timed out tree. Hide it.
const text = node.memoizedProps;
instance = cloneHiddenTextInstance(instance, text, node);
}
appendChildToContainerChildSet(containerChildSet, instance);
} else if (node.tag === HostPortal) {
// If we have a portal child, then we don't want to traverse
// down its children. Instead, we'll get insertions from each child in
// the portal directly.
} else if (
node.tag === OffscreenComponent &&
node.memoizedState !== null
) {
// The children in this boundary are hidden. Toggle their visibility
// before appending.
const child = node.child;
if (child !== null) {
child.return = node;
}
if (enablePersistentOffscreenHostContainer) {
appendAllChildrenToContainer(containerChildSet, node, false, false);
} else {
appendAllChildrenToContainer(containerChildSet, node, true, true);
}
} else if (node.child !== null) {
node.child.return = node;
node = node.child;
Expand Down Expand Up @@ -376,7 +443,7 @@ if (supportsMutation) {
const container = portalOrRoot.containerInfo;
const newChildSet = createContainerChildSet(container);
// If children might have changed, we have to add them all to the set.
appendAllChildrenToContainer(newChildSet, workInProgress);
appendAllChildrenToContainer(newChildSet, workInProgress, false, false);
portalOrRoot.pendingChildren = newChildSet;
// Schedule an update on the container to swap out the container.
markUpdate(workInProgress);
Expand Down Expand Up @@ -449,7 +516,7 @@ if (supportsMutation) {
markUpdate(workInProgress);
} else {
// If children might have changed, we have to add them all to the set.
appendAllChildren(newInstance, workInProgress);
appendAllChildren(newInstance, workInProgress, false, false);
}
};
updateHostText = function(
Expand Down Expand Up @@ -722,7 +789,7 @@ export function completeSuspendedOffscreenHostContainer(
workInProgress,
);

appendAllChildren(instance, workInProgress);
appendAllChildren(instance, workInProgress, false, false);

workInProgress.stateNode = instance;

Expand Down Expand Up @@ -869,7 +936,7 @@ function completeWork(
workInProgress,
);

appendAllChildren(instance, workInProgress);
appendAllChildren(instance, workInProgress, false, false);

workInProgress.stateNode = instance;

Expand Down
Loading

0 comments on commit 2fb2dbb

Please sign in to comment.