diff options
Diffstat (limited to 'node_modules/react-dom/lib/ReactChildFiber.js')
-rw-r--r-- | node_modules/react-dom/lib/ReactChildFiber.js | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/node_modules/react-dom/lib/ReactChildFiber.js b/node_modules/react-dom/lib/ReactChildFiber.js new file mode 100644 index 000000000..c78c63809 --- /dev/null +++ b/node_modules/react-dom/lib/ReactChildFiber.js @@ -0,0 +1,243 @@ +/** + * Copyright 2013-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +'use strict'; + +var REACT_ELEMENT_TYPE = require('./ReactElementSymbol'); + +var _require = require('./ReactCoroutine'), + REACT_COROUTINE_TYPE = _require.REACT_COROUTINE_TYPE, + REACT_YIELD_TYPE = _require.REACT_YIELD_TYPE; + +var ReactFiber = require('./ReactFiber'); +var ReactReifiedYield = require('./ReactReifiedYield'); + +var cloneFiber = ReactFiber.cloneFiber, + createFiberFromElement = ReactFiber.createFiberFromElement, + createFiberFromCoroutine = ReactFiber.createFiberFromCoroutine, + createFiberFromYield = ReactFiber.createFiberFromYield; +var createReifiedYield = ReactReifiedYield.createReifiedYield; + + +var isArray = Array.isArray; + +function ChildReconciler(shouldClone) { + + function createSubsequentChild(returnFiber, existingChild, previousSibling, newChildren, priority) { + if (typeof newChildren !== 'object' || newChildren === null) { + return previousSibling; + } + + switch (newChildren.$$typeof) { + case REACT_ELEMENT_TYPE: + { + var element = newChildren; + if (existingChild && element.type === existingChild.type && element.key === existingChild.key) { + // TODO: This is not sufficient since previous siblings could be new. + // Will fix reconciliation properly later. + var clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild; + if (!shouldClone) { + // TODO: This might be lowering the priority of nested unfinished work. + clone.pendingWorkPriority = priority; + } + clone.pendingProps = element.props; + clone.sibling = null; + clone['return'] = returnFiber; + previousSibling.sibling = clone; + return clone; + } + var child = createFiberFromElement(element, priority); + previousSibling.sibling = child; + child['return'] = returnFiber; + return child; + } + + case REACT_COROUTINE_TYPE: + { + var coroutine = newChildren; + var _child = createFiberFromCoroutine(coroutine, priority); + previousSibling.sibling = _child; + _child['return'] = returnFiber; + return _child; + } + + case REACT_YIELD_TYPE: + { + var yieldNode = newChildren; + var reifiedYield = createReifiedYield(yieldNode); + var _child2 = createFiberFromYield(yieldNode, priority); + _child2.output = reifiedYield; + previousSibling.sibling = _child2; + _child2['return'] = returnFiber; + return _child2; + } + } + + if (isArray(newChildren)) { + var prev = previousSibling; + var existing = existingChild; + for (var i = 0; i < newChildren.length; i++) { + var nextExisting = existing && existing.sibling; + prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority); + if (prev && existing) { + // TODO: This is not correct because there could've been more + // than one sibling consumed but I don't want to return a tuple. + existing = nextExisting; + } + } + return prev; + } else { + // TODO: Throw for unknown children. + return previousSibling; + } + } + + function createFirstChild(returnFiber, existingChild, newChildren, priority) { + if (typeof newChildren !== 'object' || newChildren === null) { + return null; + } + + switch (newChildren.$$typeof) { + case REACT_ELEMENT_TYPE: + { + /* $FlowFixMe(>=0.31.0): This is an unsafe cast. Consider adding a type + * annotation to the `newChildren` param of this + * function. + */ + var element = newChildren; + if (existingChild && element.type === existingChild.type && element.key === existingChild.key) { + // Get the clone of the existing fiber. + var clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild; + if (!shouldClone) { + // TODO: This might be lowering the priority of nested unfinished work. + clone.pendingWorkPriority = priority; + } + clone.pendingProps = element.props; + clone.sibling = null; + clone['return'] = returnFiber; + return clone; + } + var child = createFiberFromElement(element, priority); + child['return'] = returnFiber; + return child; + } + + case REACT_COROUTINE_TYPE: + { + /* $FlowFixMe(>=0.31.0): No 'handler' property found in object type + */ + var coroutine = newChildren; + var _child3 = createFiberFromCoroutine(coroutine, priority); + _child3['return'] = returnFiber; + return _child3; + } + + case REACT_YIELD_TYPE: + { + // A yield results in a fragment fiber whose output is the continuation. + // TODO: When there is only a single child, we can optimize this to avoid + // the fragment. + /* $FlowFixMe(>=0.31.0): No 'continuation' property found in object + * type + */ + var yieldNode = newChildren; + var reifiedYield = createReifiedYield(yieldNode); + var _child4 = createFiberFromYield(yieldNode, priority); + _child4.output = reifiedYield; + _child4['return'] = returnFiber; + return _child4; + } + } + + if (isArray(newChildren)) { + var first = null; + var prev = null; + var existing = existingChild; + /* $FlowIssue(>=0.31.0) #12747709 + * + * `Array.isArray` is matched syntactically for now until predicate + * support is complete. + */ + for (var i = 0; i < newChildren.length; i++) { + var nextExisting = existing && existing.sibling; + if (prev == null) { + prev = createFirstChild(returnFiber, existing, newChildren[i], priority); + first = prev; + } else { + prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority); + } + if (prev && existing) { + // TODO: This is not correct because there could've been more + // than one sibling consumed but I don't want to return a tuple. + existing = nextExisting; + } + } + return first; + } else { + // TODO: Throw for unknown children. + return null; + } + } + + // TODO: This API won't work because we'll need to transfer the side-effects of + // unmounting children to the returnFiber. + function reconcileChildFibers(returnFiber, currentFirstChild, newChildren, priority) { + return createFirstChild(returnFiber, currentFirstChild, newChildren, priority); + } + + return reconcileChildFibers; +} + +exports.reconcileChildFibers = ChildReconciler(true); + +exports.reconcileChildFibersInPlace = ChildReconciler(false); + +function cloneSiblings(current, workInProgress, returnFiber) { + workInProgress['return'] = returnFiber; + while (current.sibling) { + current = current.sibling; + workInProgress = workInProgress.sibling = cloneFiber(current, current.pendingWorkPriority); + workInProgress['return'] = returnFiber; + } + workInProgress.sibling = null; +} + +exports.cloneChildFibers = function (current, workInProgress) { + if (!workInProgress.child) { + return; + } + if (current && workInProgress.child === current.child) { + // We use workInProgress.child since that lets Flow know that it can't be + // null since we validated that already. However, as the line above suggests + // they're actually the same thing. + var currentChild = workInProgress.child; + // TODO: This used to reset the pending priority. Not sure if that is needed. + // workInProgress.pendingWorkPriority = current.pendingWorkPriority; + // TODO: The below priority used to be set to NoWork which would've + // dropped work. This is currently unobservable but will become + // observable when the first sibling has lower priority work remaining + // than the next sibling. At that point we should add tests that catches + // this. + var newChild = cloneFiber(currentChild, currentChild.pendingWorkPriority); + workInProgress.child = newChild; + cloneSiblings(currentChild, newChild, workInProgress); + } + + // If there is no alternate, then we don't need to clone the children. + // If the children of the alternate fiber is a different set, then we don't + // need to clone. We need to reset the return fiber though since we'll + // traverse down into them. + var child = workInProgress.child; + while (child) { + child['return'] = workInProgress; + child = child.sibling; + } +};
\ No newline at end of file |