mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Merge pull request #8400 from sebmarkbage/fibercontainerchildren
[Fiber] Update root children using appendChild/insertBefore/removeChild
This commit is contained in:
@@ -120,4 +120,3 @@ src/renderers/shared/stack/reconciler/__tests__/refs-test.js
|
||||
|
||||
src/test/__tests__/ReactTestUtils-test.js
|
||||
* traverses children in the correct order
|
||||
* should support injected wrapper components as DOM components
|
||||
|
||||
@@ -1560,6 +1560,7 @@ src/test/__tests__/ReactTestUtils-test.js
|
||||
* can scryRenderedDOMComponentsWithClass with TextComponent
|
||||
* can scryRenderedDOMComponentsWithClass with className contains \n
|
||||
* can scryRenderedDOMComponentsWithClass with multiple classes
|
||||
* should support injected wrapper components as DOM components
|
||||
* should change the value of an input field
|
||||
* should change the value of an input field in a component
|
||||
* should throw when attempting to use ReactTestUtils.Simulate with shallow rendering
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
'use strict';
|
||||
|
||||
import type { Fiber } from 'ReactFiber';
|
||||
import type { HostChildren } from 'ReactFiberReconciler';
|
||||
import type { ReactNodeList } from 'ReactTypes';
|
||||
|
||||
var ReactBrowserEventEmitter = require('ReactBrowserEventEmitter');
|
||||
@@ -39,6 +38,8 @@ var {
|
||||
} = ReactDOMFiberComponent;
|
||||
var { precacheFiberNode } = ReactDOMComponentTree;
|
||||
|
||||
const DOCUMENT_NODE = 9;
|
||||
|
||||
ReactDOMInjection.inject();
|
||||
ReactControlledComponent.injection.injectFiberControlledHostComponent(
|
||||
ReactDOMFiberComponent
|
||||
@@ -54,23 +55,6 @@ type Props = { className ?: string };
|
||||
type Instance = Element;
|
||||
type TextInstance = Text;
|
||||
|
||||
function recursivelyAppendChildren(parent : Element, child : HostChildren<Instance | TextInstance>) {
|
||||
if (!child) {
|
||||
return;
|
||||
}
|
||||
/* $FlowFixMe: Element and Text should have this property. */
|
||||
if (child.nodeType === 1 || child.nodeType === 3) {
|
||||
/* $FlowFixMe: Refinement issue. I don't know how to express different. */
|
||||
parent.appendChild(child);
|
||||
} else {
|
||||
/* As a result of the refinement issue this type isn't known. */
|
||||
let node : any = child;
|
||||
do {
|
||||
recursivelyAppendChildren(parent, node.output);
|
||||
} while (node = node.sibling);
|
||||
}
|
||||
}
|
||||
|
||||
let eventsEnabled : ?boolean = null;
|
||||
let selectionInformation : ?mixed = null;
|
||||
|
||||
@@ -89,27 +73,28 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
eventsEnabled = null;
|
||||
},
|
||||
|
||||
updateContainer(container : Container, children : HostChildren<Instance | TextInstance>) : void {
|
||||
// TODO: Containers should update similarly to other parents.
|
||||
container.innerHTML = '';
|
||||
recursivelyAppendChildren(container, children);
|
||||
},
|
||||
|
||||
createInstance(
|
||||
type : string,
|
||||
props : Props,
|
||||
children : HostChildren<Instance | TextInstance>,
|
||||
internalInstanceHandle : Object
|
||||
) : Instance {
|
||||
const root = document.body; // HACK
|
||||
const root = document.documentElement; // HACK
|
||||
|
||||
const domElement : Instance = createElement(type, props, root);
|
||||
precacheFiberNode(internalInstanceHandle, domElement);
|
||||
recursivelyAppendChildren(domElement, children);
|
||||
setInitialProperties(domElement, type, props, root);
|
||||
return domElement;
|
||||
},
|
||||
|
||||
appendInitialChild(parentInstance : Instance, child : Instance | TextInstance) : void {
|
||||
parentInstance.appendChild(child);
|
||||
},
|
||||
|
||||
finalizeInitialChildren(domElement : Instance, type : string, props : Props) : void {
|
||||
const root = document.documentElement; // HACK
|
||||
|
||||
setInitialProperties(domElement, type, props, root);
|
||||
},
|
||||
|
||||
prepareUpdate(
|
||||
domElement : Instance,
|
||||
oldProps : Props,
|
||||
@@ -125,7 +110,7 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
internalInstanceHandle : Object
|
||||
) : void {
|
||||
var type = domElement.tagName.toLowerCase(); // HACK
|
||||
var root = document.body; // HACK
|
||||
var root = document.documentElement; // HACK
|
||||
// Update the internal instance handle so that we know which props are
|
||||
// the current ones.
|
||||
precacheFiberNode(internalInstanceHandle, domElement);
|
||||
@@ -142,19 +127,19 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
textInstance.nodeValue = newText;
|
||||
},
|
||||
|
||||
appendChild(parentInstance : Instance, child : Instance | TextInstance) : void {
|
||||
appendChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
|
||||
parentInstance.appendChild(child);
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance : Instance,
|
||||
parentInstance : Instance | Container,
|
||||
child : Instance | TextInstance,
|
||||
beforeChild : Instance | TextInstance
|
||||
) : void {
|
||||
parentInstance.insertBefore(child, beforeChild);
|
||||
},
|
||||
|
||||
removeChild(parentInstance : Instance, child : Instance | TextInstance) : void {
|
||||
removeChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
|
||||
parentInstance.removeChild(child);
|
||||
},
|
||||
|
||||
@@ -180,9 +165,15 @@ function warnAboutUnstableUse() {
|
||||
warned = true;
|
||||
}
|
||||
|
||||
function renderSubtreeIntoContainer(parentComponent : ?ReactComponent<any, any, any>, element : ReactElement<any>, container : DOMContainerElement, callback: ?Function) {
|
||||
function renderSubtreeIntoContainer(parentComponent : ?ReactComponent<any, any, any>, element : ReactElement<any>, containerNode : DOMContainerElement | Document, callback: ?Function) {
|
||||
let container : DOMContainerElement =
|
||||
containerNode.nodeType === DOCUMENT_NODE ? (containerNode : any).documentElement : (containerNode : any);
|
||||
let root;
|
||||
if (!container._reactRootContainer) {
|
||||
// First clear any existing content.
|
||||
while (container.lastChild) {
|
||||
container.removeChild(container.lastChild);
|
||||
}
|
||||
root = container._reactRootContainer = DOMRenderer.mountContainer(element, container, parentComponent, callback);
|
||||
} else {
|
||||
DOMRenderer.updateContainer(element, root = container._reactRootContainer, parentComponent, callback);
|
||||
@@ -197,12 +188,12 @@ var ReactDOM = {
|
||||
return renderSubtreeIntoContainer(null, element, container, callback);
|
||||
},
|
||||
|
||||
unstable_renderSubtreeIntoContainer(parentComponent : ReactComponent<any, any, any>, element : ReactElement<any>, container : DOMContainerElement, callback: ?Function) {
|
||||
unstable_renderSubtreeIntoContainer(parentComponent : ReactComponent<any, any, any>, element : ReactElement<any>, containerNode : DOMContainerElement | Document, callback: ?Function) {
|
||||
invariant(
|
||||
parentComponent != null && ReactInstanceMap.has(parentComponent),
|
||||
'parentComponent must be a valid React Component'
|
||||
);
|
||||
return renderSubtreeIntoContainer(parentComponent, element, container, callback);
|
||||
return renderSubtreeIntoContainer(parentComponent, element, containerNode, callback);
|
||||
},
|
||||
|
||||
unmountComponentAtNode(container : DOMContainerElement) {
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
import type { Fiber } from 'ReactFiber';
|
||||
import type { UpdateQueue } from 'ReactFiberUpdateQueue';
|
||||
import type { HostChildren } from 'ReactFiberReconciler';
|
||||
|
||||
var ReactFiberReconciler = require('ReactFiberReconciler');
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
@@ -32,59 +31,35 @@ var {
|
||||
var scheduledAnimationCallback = null;
|
||||
var scheduledDeferredCallback = null;
|
||||
|
||||
const TERMINAL_TAG = 99;
|
||||
const TEXT_TAG = 98;
|
||||
|
||||
type Container = { rootID: string, children: Array<Instance | TextInstance> };
|
||||
type Props = { prop: any };
|
||||
type Instance = { tag: 99, type: string, id: number, children: Array<Instance | TextInstance>, prop: any };
|
||||
type TextInstance = { tag: 98, text: string };
|
||||
type Instance = {| type: string, id: number, children: Array<Instance | TextInstance>, prop: any |};
|
||||
type TextInstance = {| text: string, id: number |};
|
||||
|
||||
var instanceCounter = 0;
|
||||
|
||||
function recursivelyAppendChildren(
|
||||
flatArray : Array<Instance | TextInstance>,
|
||||
child : HostChildren<Instance | TextInstance>
|
||||
) {
|
||||
if (!child) {
|
||||
return;
|
||||
}
|
||||
if (child.tag === TERMINAL_TAG || child.tag === TEXT_TAG) {
|
||||
flatArray.push(child);
|
||||
} else {
|
||||
let node = child;
|
||||
do {
|
||||
recursivelyAppendChildren(flatArray, node.output);
|
||||
} while (node = node.sibling);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenChildren(children : HostChildren<Instance | TextInstance>) {
|
||||
const flatArray = [];
|
||||
recursivelyAppendChildren(flatArray, children);
|
||||
return flatArray;
|
||||
}
|
||||
|
||||
var NoopRenderer = ReactFiberReconciler({
|
||||
|
||||
updateContainer(containerInfo : Container, children : HostChildren<Instance | TextInstance>) : void {
|
||||
containerInfo.children = flattenChildren(children);
|
||||
},
|
||||
|
||||
createInstance(type : string, props : Props, children : HostChildren<Instance | TextInstance>) : Instance {
|
||||
createInstance(type : string, props : Props) : Instance {
|
||||
const inst = {
|
||||
tag: TERMINAL_TAG,
|
||||
id: instanceCounter++,
|
||||
type: type,
|
||||
children: flattenChildren(children),
|
||||
children: [],
|
||||
prop: props.prop,
|
||||
};
|
||||
// Hide from unit tests
|
||||
Object.defineProperty(inst, 'tag', { value: inst.tag, enumerable: false });
|
||||
Object.defineProperty(inst, 'id', { value: inst.id, enumerable: false });
|
||||
return inst;
|
||||
},
|
||||
|
||||
appendInitialChild(parentInstance : Instance, child : Instance | TextInstance) : void {
|
||||
parentInstance.children.push(child);
|
||||
},
|
||||
|
||||
finalizeInitialChildren(domElement : Instance, type : string, props : Props) : void {
|
||||
// Noop
|
||||
},
|
||||
|
||||
prepareUpdate(instance : Instance, oldProps : Props, newProps : Props) : boolean {
|
||||
return true;
|
||||
},
|
||||
@@ -94,9 +69,9 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
},
|
||||
|
||||
createTextInstance(text : string) : TextInstance {
|
||||
var inst = { tag: TEXT_TAG, text : text };
|
||||
var inst = { text : text, id: instanceCounter++ };
|
||||
// Hide from unit tests
|
||||
Object.defineProperty(inst, 'tag', { value: inst.tag, enumerable: false });
|
||||
Object.defineProperty(inst, 'id', { value: inst.id, enumerable: false });
|
||||
return inst;
|
||||
},
|
||||
|
||||
@@ -104,7 +79,7 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
textInstance.text = newText;
|
||||
},
|
||||
|
||||
appendChild(parentInstance : Instance, child : Instance | TextInstance) : void {
|
||||
appendChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
|
||||
const index = parentInstance.children.indexOf(child);
|
||||
if (index !== -1) {
|
||||
parentInstance.children.splice(index, 1);
|
||||
@@ -113,7 +88,7 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
},
|
||||
|
||||
insertBefore(
|
||||
parentInstance : Instance,
|
||||
parentInstance : Instance | Container,
|
||||
child : Instance | TextInstance,
|
||||
beforeChild : Instance | TextInstance
|
||||
) : void {
|
||||
@@ -128,7 +103,7 @@ var NoopRenderer = ReactFiberReconciler({
|
||||
parentInstance.children.splice(beforeIndex, 0, child);
|
||||
},
|
||||
|
||||
removeChild(parentInstance : Instance, child : Instance | TextInstance) : void {
|
||||
removeChild(parentInstance : Instance | Container, child : Instance | TextInstance) : void {
|
||||
const index = parentInstance.children.indexOf(child);
|
||||
if (index === -1) {
|
||||
throw new Error('This child does not exist.');
|
||||
@@ -213,7 +188,7 @@ var ReactNoop = {
|
||||
}
|
||||
// Unsound duck typing.
|
||||
const component = (componentOrElement : any);
|
||||
if (component.tag === TERMINAL_TAG || component.tag === TEXT_TAG) {
|
||||
if (typeof component.id === 'number') {
|
||||
return component;
|
||||
}
|
||||
const inst = ReactInstanceMap.get(component);
|
||||
@@ -278,10 +253,13 @@ var ReactNoop = {
|
||||
function logHostInstances(children: Array<Instance | TextInstance>, depth) {
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
var child = children[i];
|
||||
if (child.tag === TEXT_TAG) {
|
||||
log(' '.repeat(depth) + '- ' + child.text);
|
||||
var indent = ' '.repeat(depth);
|
||||
if (typeof child.text === 'string') {
|
||||
log(indent + '- ' + child.text);
|
||||
} else {
|
||||
log(' '.repeat(depth) + '- ' + child.type + '#' + child.id);
|
||||
// $FlowFixMe - The child should've been refined now.
|
||||
log(indent + '- ' + child.type + '#' + child.id);
|
||||
// $FlowFixMe - The child should've been refined now.
|
||||
logHostInstances(child.children, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +300,24 @@ module.exports = function<T, P, I, TI, C>(
|
||||
}
|
||||
|
||||
function updatePortalComponent(current, workInProgress) {
|
||||
reconcileChildren(current, workInProgress, workInProgress.pendingProps);
|
||||
const priorityLevel = workInProgress.pendingWorkPriority;
|
||||
const nextChildren = workInProgress.pendingProps;
|
||||
if (!current) {
|
||||
// Portals are special because we don't append the children during mount
|
||||
// but at commit. Therefore we need to track insertions which the normal
|
||||
// flow doesn't do during mount. This doesn't happen at the root because
|
||||
// the root always starts with a "current" with a null child.
|
||||
// TODO: Consider unifying this with how the root works.
|
||||
workInProgress.child = reconcileChildFibersInPlace(
|
||||
workInProgress,
|
||||
workInProgress.child,
|
||||
nextChildren,
|
||||
priorityLevel
|
||||
);
|
||||
markChildAsProgressed(current, workInProgress, priorityLevel);
|
||||
} else {
|
||||
reconcileChildren(current, workInProgress, nextChildren);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
'use strict';
|
||||
|
||||
import type { Fiber } from 'ReactFiber';
|
||||
import type { FiberRoot } from 'ReactFiberRoot';
|
||||
import type { HostConfig } from 'ReactFiberReconciler';
|
||||
|
||||
var ReactTypeOfWork = require('ReactTypeOfWork');
|
||||
@@ -37,7 +36,6 @@ module.exports = function<T, P, I, TI, C>(
|
||||
trapError : (failedFiber : Fiber, error: Error, isUnmounting : boolean) => void
|
||||
) {
|
||||
|
||||
const updateContainer = config.updateContainer;
|
||||
const commitUpdate = config.commitUpdate;
|
||||
const commitTextUpdate = config.commitTextUpdate;
|
||||
|
||||
@@ -68,20 +66,28 @@ module.exports = function<T, P, I, TI, C>(
|
||||
}
|
||||
}
|
||||
|
||||
function getHostParent(fiber : Fiber) : ?I {
|
||||
function getHostParent(fiber : Fiber) : I | C {
|
||||
let parent = fiber.return;
|
||||
while (parent) {
|
||||
switch (parent.tag) {
|
||||
case HostComponent:
|
||||
return parent.stateNode;
|
||||
case HostContainer:
|
||||
// TODO: Currently we use the updateContainer feature to update these,
|
||||
// but we should be able to handle this case too.
|
||||
return null;
|
||||
return parent.stateNode.containerInfo;
|
||||
case Portal:
|
||||
return parent.stateNode.containerInfo;
|
||||
}
|
||||
parent = parent.return;
|
||||
}
|
||||
return null;
|
||||
throw new Error('Expected to find a host parent.');
|
||||
}
|
||||
|
||||
function isHostParent(fiber : Fiber) : boolean {
|
||||
return (
|
||||
fiber.tag === HostComponent ||
|
||||
fiber.tag === HostContainer ||
|
||||
fiber.tag === Portal
|
||||
);
|
||||
}
|
||||
|
||||
function getHostSibling(fiber : Fiber) : ?I {
|
||||
@@ -93,7 +99,7 @@ module.exports = function<T, P, I, TI, C>(
|
||||
siblings: while (true) {
|
||||
// If we didn't find anything, let's try the next sibling.
|
||||
while (!node.sibling) {
|
||||
if (!node.return || node.return.tag === HostComponent) {
|
||||
if (!node.return || isHostParent(node.return)) {
|
||||
// If we pop out of the root or hit the parent the fiber we are the
|
||||
// last sibling.
|
||||
return null;
|
||||
@@ -128,9 +134,6 @@ module.exports = function<T, P, I, TI, C>(
|
||||
function commitInsertion(finishedWork : Fiber) : void {
|
||||
// Recursively insert all host nodes into the parent.
|
||||
const parent = getHostParent(finishedWork);
|
||||
if (!parent) {
|
||||
return;
|
||||
}
|
||||
const before = getHostSibling(finishedWork);
|
||||
// We only have the top Fiber that was inserted but we need recurse down its
|
||||
// children to find all the terminal nodes.
|
||||
@@ -142,6 +145,10 @@ module.exports = function<T, P, I, TI, C>(
|
||||
} else {
|
||||
appendChild(parent, node.stateNode);
|
||||
}
|
||||
} else if (node.tag === Portal) {
|
||||
// If the insertion itself is a portal, 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.child) {
|
||||
// TODO: Coroutines need to visit the stateNode.
|
||||
node = node.child;
|
||||
@@ -198,8 +205,14 @@ module.exports = function<T, P, I, TI, C>(
|
||||
commitNestedUnmounts(node);
|
||||
// After all the children have unmounted, it is now safe to remove the
|
||||
// node from the tree.
|
||||
if (parent) {
|
||||
removeChild(parent, node.stateNode);
|
||||
removeChild(parent, node.stateNode);
|
||||
} else if (node.tag === Portal) {
|
||||
// When we go into a portal, it becomes the parent to remove from.
|
||||
// We will reassign it back when we pop the portal on the way up.
|
||||
parent = node.stateNode.containerInfo;
|
||||
if (node.child) {
|
||||
node = node.child;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
commitUnmount(node);
|
||||
@@ -218,6 +231,11 @@ module.exports = function<T, P, I, TI, C>(
|
||||
return;
|
||||
}
|
||||
node = node.return;
|
||||
if (node.tag === Portal) {
|
||||
// When we go out of the portal, we need to restore the parent.
|
||||
// Since we don't keep a stack of them, we will search for it.
|
||||
parent = getHostParent(node);
|
||||
}
|
||||
}
|
||||
node.sibling.return = node.return;
|
||||
node = node.sibling;
|
||||
@@ -260,11 +278,6 @@ module.exports = function<T, P, I, TI, C>(
|
||||
detachRef(current);
|
||||
return;
|
||||
}
|
||||
case Portal: {
|
||||
const containerInfo : C = current.stateNode.containerInfo;
|
||||
updateContainer(containerInfo, null);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,14 +287,6 @@ module.exports = function<T, P, I, TI, C>(
|
||||
detachRefIfNeeded(current, finishedWork);
|
||||
return;
|
||||
}
|
||||
case HostContainer: {
|
||||
// TODO: Attach children to root container.
|
||||
const children = finishedWork.output;
|
||||
const root : FiberRoot = finishedWork.stateNode;
|
||||
const containerInfo : C = root.containerInfo;
|
||||
updateContainer(containerInfo, children);
|
||||
return;
|
||||
}
|
||||
case HostComponent: {
|
||||
const instance : I = finishedWork.stateNode;
|
||||
if (instance != null && current) {
|
||||
@@ -303,10 +308,10 @@ module.exports = function<T, P, I, TI, C>(
|
||||
commitTextUpdate(textInstance, oldText, newText);
|
||||
return;
|
||||
}
|
||||
case HostContainer: {
|
||||
return;
|
||||
}
|
||||
case Portal: {
|
||||
const children = finishedWork.child;
|
||||
const containerInfo : C = finishedWork.stateNode.containerInfo;
|
||||
updateContainer(containerInfo, children);
|
||||
return;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -46,6 +46,8 @@ var {
|
||||
module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
|
||||
const createInstance = config.createInstance;
|
||||
const appendInitialChild = config.appendInitialChild;
|
||||
const finalizeInitialChildren = config.finalizeInitialChildren;
|
||||
const createTextInstance = config.createTextInstance;
|
||||
const prepareUpdate = config.prepareUpdate;
|
||||
|
||||
@@ -124,6 +126,35 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
return workInProgress.stateNode;
|
||||
}
|
||||
|
||||
function appendAllChildren(parent : I, workInProgress : Fiber) {
|
||||
// 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) {
|
||||
if (node.tag === HostComponent || node.tag === HostText) {
|
||||
appendInitialChild(parent, node.stateNode);
|
||||
} else if (node.tag === Portal) {
|
||||
// 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.child) {
|
||||
// TODO: Coroutines need to visit the stateNode.
|
||||
node = node.child;
|
||||
continue;
|
||||
}
|
||||
if (node === workInProgress) {
|
||||
return;
|
||||
}
|
||||
while (!node.sibling) {
|
||||
if (!node.return || node.return === workInProgress) {
|
||||
return;
|
||||
}
|
||||
node = node.return;
|
||||
}
|
||||
node = node.sibling;
|
||||
}
|
||||
}
|
||||
|
||||
function completeWork(current : ?Fiber, workInProgress : Fiber) : ?Fiber {
|
||||
switch (workInProgress.tag) {
|
||||
case FunctionalComponent:
|
||||
@@ -167,11 +198,8 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
fiberRoot.context = fiberRoot.pendingContext;
|
||||
fiberRoot.pendingContext = null;
|
||||
}
|
||||
// We don't know if a container has updated any children so we always
|
||||
// need to update it right now. We schedule this side-effect before
|
||||
// all the other side-effects in the subtree. We need to schedule it
|
||||
// before so that the entire tree is up-to-date before the life-cycles
|
||||
// are invoked.
|
||||
// TODO: Only mark this as an update if we have any pending callbacks
|
||||
// on it.
|
||||
markUpdate(workInProgress);
|
||||
return null;
|
||||
}
|
||||
@@ -204,9 +232,16 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const child = workInProgress.child;
|
||||
const children = (child && !child.sibling) ? (child.output : ?Fiber | I) : child;
|
||||
const instance = createInstance(workInProgress.type, newProps, children, workInProgress);
|
||||
|
||||
// TODO: Move createInstance to beginWork and keep it on a context
|
||||
// "stack" as the parent. Then append children as we go in beginWork
|
||||
// or completeWork depending on we want to add then top->down or
|
||||
// bottom->up. Top->down is faster in IE11.
|
||||
// Finally, finalizeInitialChildren here in completeWork.
|
||||
const instance = createInstance(workInProgress.type, newProps, workInProgress);
|
||||
appendAllChildren(instance, workInProgress);
|
||||
finalizeInitialChildren(instance, workInProgress.type, newProps);
|
||||
|
||||
// TODO: This seems like unnecessary duplication.
|
||||
workInProgress.stateNode = instance;
|
||||
workInProgress.output = instance;
|
||||
@@ -253,6 +288,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
transferOutput(workInProgress.child, workInProgress);
|
||||
return null;
|
||||
case Portal:
|
||||
// TODO: Only mark this as an update if we have any pending callbacks.
|
||||
markUpdate(workInProgress);
|
||||
workInProgress.output = null;
|
||||
workInProgress.memoizedProps = workInProgress.pendingProps;
|
||||
|
||||
@@ -47,22 +47,19 @@ type OpaqueNode = Fiber;
|
||||
|
||||
export type HostConfig<T, P, I, TI, C> = {
|
||||
|
||||
// TODO: We don't currently have a quick way to detect that children didn't
|
||||
// reorder so we host will always need to check the set. We should make a flag
|
||||
// or something so that it can bailout easily.
|
||||
createInstance(type : T, props : P, internalInstanceHandle : OpaqueNode) : I,
|
||||
appendInitialChild(parentInstance : I, child : I) : void,
|
||||
finalizeInitialChildren(parentInstance : I, type : T, props : P) : void,
|
||||
|
||||
updateContainer(containerInfo : C, children : HostChildren<I | TI>) : void,
|
||||
|
||||
createInstance(type : T, props : P, children : HostChildren<I | TI>, internalInstanceHandle : OpaqueNode) : I,
|
||||
prepareUpdate(instance : I, oldProps : P, newProps : P) : boolean,
|
||||
commitUpdate(instance : I, oldProps : P, newProps : P, internalInstanceHandle : OpaqueNode) : void,
|
||||
|
||||
createTextInstance(text : string, internalInstanceHandle : OpaqueNode) : TI,
|
||||
commitTextUpdate(textInstance : TI, oldText : string, newText : string) : void,
|
||||
|
||||
appendChild(parentInstance : I, child : I | TI) : void,
|
||||
insertBefore(parentInstance : I, child : I | TI, beforeChild : I | TI) : void,
|
||||
removeChild(parentInstance : I, child : I | TI) : void,
|
||||
appendChild(parentInstance : I | C, child : I | TI) : void,
|
||||
insertBefore(parentInstance : I | C, child : I | TI, beforeChild : I | TI) : void,
|
||||
removeChild(parentInstance : I | C, child : I | TI) : void,
|
||||
|
||||
scheduleAnimationCallback(callback : () => void) : void,
|
||||
scheduleDeferredCallback(callback : (deadline : Deadline) => void) : void,
|
||||
|
||||
Reference in New Issue
Block a user