/** @license React v16.2.0
* react-test-renderer.development.js
*
* Copyright (c) 2013-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
'use strict';
if (process.env.NODE_ENV !== "production") {
(function() {
'use strict';
var _assign = require('object-assign');
var invariant = require('fbjs/lib/invariant');
var warning = require('fbjs/lib/warning');
var React = require('react');
var emptyObject = require('fbjs/lib/emptyObject');
var checkPropTypes = require('prop-types/checkPropTypes');
var shallowEqual = require('fbjs/lib/shallowEqual');
/**
* WARNING: DO NOT manually require this module.
* This is a replacement for `invariant(...)` used by the error code system
* and will _only_ be required by the corresponding babel pass.
* It always throws.
*/
var enableAsyncSubtreeAPI = true;
// Exports ReactDOM.createRoot
var enableUserTimingAPI = true;
// Mutating mode (React DOM, React ART, React Native):
var enableMutatingReconciler = true;
// Experimental noop mode (currently unused):
var enableNoopReconciler = false;
// Experimental persistent mode (CS):
var enablePersistentReconciler = false;
// Helps identify side effects in begin-phase lifecycle hooks and setState reducers:
var debugRenderPhaseSideEffects = false;
// Only used in www builds.
/**
* `ReactInstanceMap` maintains a mapping from a public facing stateful
* instance (key) and the internal representation (value). This allows public
* methods to accept the user facing instance as an argument and map them back
* to internal methods.
*
* Note that this module is currently shared and assumed to be stateless.
* If this becomes an actual Map, that will break.
*/
/**
* This API should be called `delete` but we'd have to make sure to always
* transform these to strings for IE support. When this transform is fully
* supported we can rename it.
*/
function get(key) {
return key._reactInternalFiber;
}
function set(key, value) {
key._reactInternalFiber = value;
}
var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
var ReactCurrentOwner = ReactInternals.ReactCurrentOwner;
var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame;
function getComponentName(fiber) {
var type = fiber.type;
if (typeof type === 'string') {
return type;
}
if (typeof type === 'function') {
return type.displayName || type.name;
}
return null;
}
var IndeterminateComponent = 0; // Before we know whether it is functional or class
var FunctionalComponent = 1;
var ClassComponent = 2;
var HostRoot = 3; // Root of a host tree. Could be nested inside another node.
var HostPortal = 4; // A subtree. Could be an entry point to a different renderer.
var HostComponent = 5;
var HostText = 6;
var CallComponent = 7;
var CallHandlerPhase = 8;
var ReturnComponent = 9;
var Fragment = 10;
// Don't change these two values:
var NoEffect = 0; // 0b00000000
var PerformedWork = 1; // 0b00000001
// You can change the rest (and add more).
var Placement = 2; // 0b00000010
var Update = 4; // 0b00000100
var PlacementAndUpdate = 6; // 0b00000110
var Deletion = 8; // 0b00001000
var ContentReset = 16; // 0b00010000
var Callback = 32; // 0b00100000
var Err = 64; // 0b01000000
var Ref = 128; // 0b10000000
var MOUNTING = 1;
var MOUNTED = 2;
var UNMOUNTED = 3;
function isFiberMountedImpl(fiber) {
var node = fiber;
if (!fiber.alternate) {
// If there is no alternate, this might be a new tree that isn't inserted
// yet. If it is, then it will have a pending insertion effect on it.
if ((node.effectTag & Placement) !== NoEffect) {
return MOUNTING;
}
while (node['return']) {
node = node['return'];
if ((node.effectTag & Placement) !== NoEffect) {
return MOUNTING;
}
}
} else {
while (node['return']) {
node = node['return'];
}
}
if (node.tag === HostRoot) {
// TODO: Check if this was a nested HostRoot when used with
// renderContainerIntoSubtree.
return MOUNTED;
}
// If we didn't hit the root, that means that we're in an disconnected tree
// that has been unmounted.
return UNMOUNTED;
}
function isFiberMounted(fiber) {
return isFiberMountedImpl(fiber) === MOUNTED;
}
function isMounted(component) {
{
var owner = ReactCurrentOwner.current;
if (owner !== null && owner.tag === ClassComponent) {
var ownerFiber = owner;
var instance = ownerFiber.stateNode;
warning(instance._warnedAboutRefsInRender, '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(ownerFiber) || 'A component');
instance._warnedAboutRefsInRender = true;
}
}
var fiber = get(component);
if (!fiber) {
return false;
}
return isFiberMountedImpl(fiber) === MOUNTED;
}
function assertIsMounted(fiber) {
!(isFiberMountedImpl(fiber) === MOUNTED) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0;
}
function findCurrentFiberUsingSlowPath(fiber) {
var alternate = fiber.alternate;
if (!alternate) {
// If there is no alternate, then we only need to check if it is mounted.
var state = isFiberMountedImpl(fiber);
!(state !== UNMOUNTED) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0;
if (state === MOUNTING) {
return null;
}
return fiber;
}
// If we have two possible branches, we'll walk backwards up to the root
// to see what path the root points to. On the way we may hit one of the
// special cases and we'll deal with them.
var a = fiber;
var b = alternate;
while (true) {
var parentA = a['return'];
var parentB = parentA ? parentA.alternate : null;
if (!parentA || !parentB) {
// We're at the root.
break;
}
// If both copies of the parent fiber point to the same child, we can
// assume that the child is current. This happens when we bailout on low
// priority: the bailed out fiber's child reuses the current child.
if (parentA.child === parentB.child) {
var child = parentA.child;
while (child) {
if (child === a) {
// We've determined that A is the current branch.
assertIsMounted(parentA);
return fiber;
}
if (child === b) {
// We've determined that B is the current branch.
assertIsMounted(parentA);
return alternate;
}
child = child.sibling;
}
// We should never have an alternate for any mounting node. So the only
// way this could possibly happen is if this was unmounted, if at all.
invariant(false, 'Unable to find node on an unmounted component.');
}
if (a['return'] !== b['return']) {
// The return pointer of A and the return pointer of B point to different
// fibers. We assume that return pointers never criss-cross, so A must
// belong to the child set of A.return, and B must belong to the child
// set of B.return.
a = parentA;
b = parentB;
} else {
// The return pointers point to the same fiber. We'll have to use the
// default, slow path: scan the child sets of each parent alternate to see
// which child belongs to which set.
//
// Search parent A's child set
var didFindChild = false;
var _child = parentA.child;
while (_child) {
if (_child === a) {
didFindChild = true;
a = parentA;
b = parentB;
break;
}
if (_child === b) {
didFindChild = true;
b = parentA;
a = parentB;
break;
}
_child = _child.sibling;
}
if (!didFindChild) {
// Search parent B's child set
_child = parentB.child;
while (_child) {
if (_child === a) {
didFindChild = true;
a = parentB;
b = parentA;
break;
}
if (_child === b) {
didFindChild = true;
b = parentB;
a = parentA;
break;
}
_child = _child.sibling;
}
!didFindChild ? invariant(false, 'Child was not found in either parent set. This indicates a bug in React related to the return pointer. Please file an issue.') : void 0;
}
}
!(a.alternate === b) ? invariant(false, 'Return fibers should always be each others\' alternates. This error is likely caused by a bug in React. Please file an issue.') : void 0;
}
// If the root is not a host container, we're in a disconnected tree. I.e.
// unmounted.
!(a.tag === HostRoot) ? invariant(false, 'Unable to find node on an unmounted component.') : void 0;
if (a.stateNode.current === a) {
// We've determined that A is the current branch.
return fiber;
}
// Otherwise B has to be current branch.
return alternate;
}
function findCurrentHostFiber(parent) {
var currentParent = findCurrentFiberUsingSlowPath(parent);
if (!currentParent) {
return null;
}
// Next we'll drill down this component to find the first HostComponent/Text.
var node = currentParent;
while (true) {
if (node.tag === HostComponent || node.tag === HostText) {
return node;
} else if (node.child) {
node.child['return'] = node;
node = node.child;
continue;
}
if (node === currentParent) {
return null;
}
while (!node.sibling) {
if (!node['return'] || node['return'] === currentParent) {
return null;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
// Flow needs the return null here, but ESLint complains about it.
// eslint-disable-next-line no-unreachable
return null;
}
function findCurrentHostFiberWithNoPortals(parent) {
var currentParent = findCurrentFiberUsingSlowPath(parent);
if (!currentParent) {
return null;
}
// Next we'll drill down this component to find the first HostComponent/Text.
var node = currentParent;
while (true) {
if (node.tag === HostComponent || node.tag === HostText) {
return node;
} else if (node.child && node.tag !== HostPortal) {
node.child['return'] = node;
node = node.child;
continue;
}
if (node === currentParent) {
return null;
}
while (!node.sibling) {
if (!node['return'] || node['return'] === currentParent) {
return null;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
// Flow needs the return null here, but ESLint complains about it.
// eslint-disable-next-line no-unreachable
return null;
}
var valueStack = [];
{
var fiberStack = [];
}
var index = -1;
function createCursor(defaultValue) {
return {
current: defaultValue
};
}
function pop(cursor, fiber) {
if (index < 0) {
{
warning(false, 'Unexpected pop.');
}
return;
}
{
if (fiber !== fiberStack[index]) {
warning(false, 'Unexpected Fiber popped.');
}
}
cursor.current = valueStack[index];
valueStack[index] = null;
{
fiberStack[index] = null;
}
index--;
}
function push(cursor, value, fiber) {
index++;
valueStack[index] = cursor.current;
{
fiberStack[index] = fiber;
}
cursor.current = value;
}
function reset() {
while (index > -1) {
valueStack[index] = null;
{
fiberStack[index] = null;
}
index--;
}
}
var describeComponentFrame = function (name, source, ownerName) {
return '\n in ' + (name || 'Unknown') + (source ? ' (at ' + source.fileName.replace(/^.*[\\\/]/, '') + ':' + source.lineNumber + ')' : ownerName ? ' (created by ' + ownerName + ')' : '');
};
function describeFiber(fiber) {
switch (fiber.tag) {
case IndeterminateComponent:
case FunctionalComponent:
case ClassComponent:
case HostComponent:
var owner = fiber._debugOwner;
var source = fiber._debugSource;
var name = getComponentName(fiber);
var ownerName = null;
if (owner) {
ownerName = getComponentName(owner);
}
return describeComponentFrame(name, source, ownerName);
default:
return '';
}
}
// This function can only be called with a work-in-progress fiber and
// only during begin or complete phase. Do not call it under any other
// circumstances.
function getStackAddendumByWorkInProgressFiber(workInProgress) {
var info = '';
var node = workInProgress;
do {
info += describeFiber(node);
// Otherwise this return pointer might point to the wrong tree:
node = node['return'];
} while (node);
return info;
}
function getCurrentFiberOwnerName() {
{
var fiber = ReactDebugCurrentFiber.current;
if (fiber === null) {
return null;
}
var owner = fiber._debugOwner;
if (owner !== null && typeof owner !== 'undefined') {
return getComponentName(owner);
}
}
return null;
}
function getCurrentFiberStackAddendum() {
{
var fiber = ReactDebugCurrentFiber.current;
if (fiber === null) {
return null;
}
// Safe because if current fiber exists, we are reconciling,
// and it is guaranteed to be the work-in-progress version.
return getStackAddendumByWorkInProgressFiber(fiber);
}
return null;
}
function resetCurrentFiber() {
ReactDebugCurrentFrame.getCurrentStack = null;
ReactDebugCurrentFiber.current = null;
ReactDebugCurrentFiber.phase = null;
}
function setCurrentFiber(fiber) {
ReactDebugCurrentFrame.getCurrentStack = getCurrentFiberStackAddendum;
ReactDebugCurrentFiber.current = fiber;
ReactDebugCurrentFiber.phase = null;
}
function setCurrentPhase(phase) {
ReactDebugCurrentFiber.phase = phase;
}
var ReactDebugCurrentFiber = {
current: null,
phase: null,
resetCurrentFiber: resetCurrentFiber,
setCurrentFiber: setCurrentFiber,
setCurrentPhase: setCurrentPhase,
getCurrentFiberOwnerName: getCurrentFiberOwnerName,
getCurrentFiberStackAddendum: getCurrentFiberStackAddendum
};
// Prefix measurements so that it's possible to filter them.
// Longer prefixes are hard to read in DevTools.
var reactEmoji = '\u269B';
var warningEmoji = '\u26D4';
var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function';
// Keep track of current fiber so that we know the path to unwind on pause.
// TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them?
var currentFiber = null;
// If we're in the middle of user code, which fiber and method is it?
// Reusing `currentFiber` would be confusing for this because user code fiber
// can change during commit phase too, but we don't need to unwind it (since
// lifecycles in the commit phase don't resemble a tree).
var currentPhase = null;
var currentPhaseFiber = null;
// Did lifecycle hook schedule an update? This is often a performance problem,
// so we will keep track of it, and include it in the report.
// Track commits caused by cascading updates.
var isCommitting = false;
var hasScheduledUpdateInCurrentCommit = false;
var hasScheduledUpdateInCurrentPhase = false;
var commitCountInCurrentWorkLoop = 0;
var effectCountInCurrentCommit = 0;
var isWaitingForCallback = false;
// During commits, we only show a measurement once per method name
// to avoid stretch the commit phase with measurement overhead.
var labelsInCurrentCommit = new Set();
var formatMarkName = function (markName) {
return reactEmoji + ' ' + markName;
};
var formatLabel = function (label, warning$$1) {
var prefix = warning$$1 ? warningEmoji + ' ' : reactEmoji + ' ';
var suffix = warning$$1 ? ' Warning: ' + warning$$1 : '';
return '' + prefix + label + suffix;
};
var beginMark = function (markName) {
performance.mark(formatMarkName(markName));
};
var clearMark = function (markName) {
performance.clearMarks(formatMarkName(markName));
};
var endMark = function (label, markName, warning$$1) {
var formattedMarkName = formatMarkName(markName);
var formattedLabel = formatLabel(label, warning$$1);
try {
performance.measure(formattedLabel, formattedMarkName);
} catch (err) {}
// If previous mark was missing for some reason, this will throw.
// This could only happen if React crashed in an unexpected place earlier.
// Don't pile on with more errors.
// Clear marks immediately to avoid growing buffer.
performance.clearMarks(formattedMarkName);
performance.clearMeasures(formattedLabel);
};
var getFiberMarkName = function (label, debugID) {
return label + ' (#' + debugID + ')';
};
var getFiberLabel = function (componentName, isMounted, phase) {
if (phase === null) {
// These are composite component total time measurements.
return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']';
} else {
// Composite component methods.
return componentName + '.' + phase;
}
};
var beginFiberMark = function (fiber, phase) {
var componentName = getComponentName(fiber) || 'Unknown';
var debugID = fiber._debugID;
var isMounted = fiber.alternate !== null;
var label = getFiberLabel(componentName, isMounted, phase);
if (isCommitting && labelsInCurrentCommit.has(label)) {
// During the commit phase, we don't show duplicate labels because
// there is a fixed overhead for every measurement, and we don't
// want to stretch the commit phase beyond necessary.
return false;
}
labelsInCurrentCommit.add(label);
var markName = getFiberMarkName(label, debugID);
beginMark(markName);
return true;
};
var clearFiberMark = function (fiber, phase) {
var componentName = getComponentName(fiber) || 'Unknown';
var debugID = fiber._debugID;
var isMounted = fiber.alternate !== null;
var label = getFiberLabel(componentName, isMounted, phase);
var markName = getFiberMarkName(label, debugID);
clearMark(markName);
};
var endFiberMark = function (fiber, phase, warning$$1) {
var componentName = getComponentName(fiber) || 'Unknown';
var debugID = fiber._debugID;
var isMounted = fiber.alternate !== null;
var label = getFiberLabel(componentName, isMounted, phase);
var markName = getFiberMarkName(label, debugID);
endMark(label, markName, warning$$1);
};
var shouldIgnoreFiber = function (fiber) {
// Host components should be skipped in the timeline.
// We could check typeof fiber.type, but does this work with RN?
switch (fiber.tag) {
case HostRoot:
case HostComponent:
case HostText:
case HostPortal:
case ReturnComponent:
case Fragment:
return true;
default:
return false;
}
};
var clearPendingPhaseMeasurement = function () {
if (currentPhase !== null && currentPhaseFiber !== null) {
clearFiberMark(currentPhaseFiber, currentPhase);
}
currentPhaseFiber = null;
currentPhase = null;
hasScheduledUpdateInCurrentPhase = false;
};
var pauseTimers = function () {
// Stops all currently active measurements so that they can be resumed
// if we continue in a later deferred loop from the same unit of work.
var fiber = currentFiber;
while (fiber) {
if (fiber._debugIsCurrentlyTiming) {
endFiberMark(fiber, null, null);
}
fiber = fiber['return'];
}
};
var resumeTimersRecursively = function (fiber) {
if (fiber['return'] !== null) {
resumeTimersRecursively(fiber['return']);
}
if (fiber._debugIsCurrentlyTiming) {
beginFiberMark(fiber, null);
}
};
var resumeTimers = function () {
// Resumes all measurements that were active during the last deferred loop.
if (currentFiber !== null) {
resumeTimersRecursively(currentFiber);
}
};
function recordEffect() {
if (enableUserTimingAPI) {
effectCountInCurrentCommit++;
}
}
function recordScheduleUpdate() {
if (enableUserTimingAPI) {
if (isCommitting) {
hasScheduledUpdateInCurrentCommit = true;
}
if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') {
hasScheduledUpdateInCurrentPhase = true;
}
}
}
function startRequestCallbackTimer() {
if (enableUserTimingAPI) {
if (supportsUserTiming && !isWaitingForCallback) {
isWaitingForCallback = true;
beginMark('(Waiting for async callback...)');
}
}
}
function stopRequestCallbackTimer(didExpire) {
if (enableUserTimingAPI) {
if (supportsUserTiming) {
isWaitingForCallback = false;
var warning$$1 = didExpire ? 'React was blocked by main thread' : null;
endMark('(Waiting for async callback...)', '(Waiting for async callback...)', warning$$1);
}
}
}
function startWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// If we pause, this is the fiber to unwind from.
currentFiber = fiber;
if (!beginFiberMark(fiber, null)) {
return;
}
fiber._debugIsCurrentlyTiming = true;
}
}
function cancelWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// Remember we shouldn't complete measurement for this fiber.
// Otherwise flamechart will be deep even for small updates.
fiber._debugIsCurrentlyTiming = false;
clearFiberMark(fiber, null);
}
}
function stopWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// If we pause, its parent is the fiber to unwind from.
currentFiber = fiber['return'];
if (!fiber._debugIsCurrentlyTiming) {
return;
}
fiber._debugIsCurrentlyTiming = false;
endFiberMark(fiber, null, null);
}
}
function stopFailedWorkTimer(fiber) {
if (enableUserTimingAPI) {
if (!supportsUserTiming || shouldIgnoreFiber(fiber)) {
return;
}
// If we pause, its parent is the fiber to unwind from.
currentFiber = fiber['return'];
if (!fiber._debugIsCurrentlyTiming) {
return;
}
fiber._debugIsCurrentlyTiming = false;
var warning$$1 = 'An error was thrown inside this error boundary';
endFiberMark(fiber, null, warning$$1);
}
}
function startPhaseTimer(fiber, phase) {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
clearPendingPhaseMeasurement();
if (!beginFiberMark(fiber, phase)) {
return;
}
currentPhaseFiber = fiber;
currentPhase = phase;
}
}
function stopPhaseTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
if (currentPhase !== null && currentPhaseFiber !== null) {
var warning$$1 = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null;
endFiberMark(currentPhaseFiber, currentPhase, warning$$1);
}
currentPhase = null;
currentPhaseFiber = null;
}
}
function startWorkLoopTimer(nextUnitOfWork) {
if (enableUserTimingAPI) {
currentFiber = nextUnitOfWork;
if (!supportsUserTiming) {
return;
}
commitCountInCurrentWorkLoop = 0;
// This is top level call.
// Any other measurements are performed within.
beginMark('(React Tree Reconciliation)');
// Resume any measurements that were in progress during the last loop.
resumeTimers();
}
}
function stopWorkLoopTimer(interruptedBy) {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var warning$$1 = null;
if (interruptedBy !== null) {
if (interruptedBy.tag === HostRoot) {
warning$$1 = 'A top-level update interrupted the previous render';
} else {
var componentName = getComponentName(interruptedBy) || 'Unknown';
warning$$1 = 'An update to ' + componentName + ' interrupted the previous render';
}
} else if (commitCountInCurrentWorkLoop > 1) {
warning$$1 = 'There were cascading updates';
}
commitCountInCurrentWorkLoop = 0;
// Pause any measurements until the next loop.
pauseTimers();
endMark('(React Tree Reconciliation)', '(React Tree Reconciliation)', warning$$1);
}
}
function startCommitTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
isCommitting = true;
hasScheduledUpdateInCurrentCommit = false;
labelsInCurrentCommit.clear();
beginMark('(Committing Changes)');
}
}
function stopCommitTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var warning$$1 = null;
if (hasScheduledUpdateInCurrentCommit) {
warning$$1 = 'Lifecycle hook scheduled a cascading update';
} else if (commitCountInCurrentWorkLoop > 0) {
warning$$1 = 'Caused by a cascading update in earlier commit';
}
hasScheduledUpdateInCurrentCommit = false;
commitCountInCurrentWorkLoop++;
isCommitting = false;
labelsInCurrentCommit.clear();
endMark('(Committing Changes)', '(Committing Changes)', warning$$1);
}
}
function startCommitHostEffectsTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
effectCountInCurrentCommit = 0;
beginMark('(Committing Host Effects)');
}
}
function stopCommitHostEffectsTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var count = effectCountInCurrentCommit;
effectCountInCurrentCommit = 0;
endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null);
}
}
function startCommitLifeCyclesTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
effectCountInCurrentCommit = 0;
beginMark('(Calling Lifecycle Methods)');
}
}
function stopCommitLifeCyclesTimer() {
if (enableUserTimingAPI) {
if (!supportsUserTiming) {
return;
}
var count = effectCountInCurrentCommit;
effectCountInCurrentCommit = 0;
endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null);
}
}
{
var warnedAboutMissingGetChildContext = {};
}
// A cursor to the current merged context object on the stack.
var contextStackCursor = createCursor(emptyObject);
// A cursor to a boolean indicating whether the context has changed.
var didPerformWorkStackCursor = createCursor(false);
// Keep track of the previous context object that was on the stack.
// We use this to get access to the parent context after we have already
// pushed the next context provider, and now need to merge their contexts.
var previousContext = emptyObject;
function getUnmaskedContext(workInProgress) {
var hasOwnContext = isContextProvider(workInProgress);
if (hasOwnContext) {
// If the fiber is a context provider itself, when we read its context
// we have already pushed its own child context on the stack. A context
// provider should not "see" its own child context. Therefore we read the
// previous (parent) context instead for a context provider.
return previousContext;
}
return contextStackCursor.current;
}
function cacheContext(workInProgress, unmaskedContext, maskedContext) {
var instance = workInProgress.stateNode;
instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext;
instance.__reactInternalMemoizedMaskedChildContext = maskedContext;
}
function getMaskedContext(workInProgress, unmaskedContext) {
var type = workInProgress.type;
var contextTypes = type.contextTypes;
if (!contextTypes) {
return emptyObject;
}
// Avoid recreating masked context unless unmasked context has changed.
// Failing to do this will result in unnecessary calls to componentWillReceiveProps.
// This may trigger infinite loops if componentWillReceiveProps calls setState.
var instance = workInProgress.stateNode;
if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) {
return instance.__reactInternalMemoizedMaskedChildContext;
}
var context = {};
for (var key in contextTypes) {
context[key] = unmaskedContext[key];
}
{
var name = getComponentName(workInProgress) || 'Unknown';
checkPropTypes(contextTypes, context, 'context', name, ReactDebugCurrentFiber.getCurrentFiberStackAddendum);
}
// Cache unmasked context so we can avoid recreating masked context unless necessary.
// Context is created before the class component is instantiated so check for instance.
if (instance) {
cacheContext(workInProgress, unmaskedContext, context);
}
return context;
}
function hasContextChanged() {
return didPerformWorkStackCursor.current;
}
function isContextConsumer(fiber) {
return fiber.tag === ClassComponent && fiber.type.contextTypes != null;
}
function isContextProvider(fiber) {
return fiber.tag === ClassComponent && fiber.type.childContextTypes != null;
}
function popContextProvider(fiber) {
if (!isContextProvider(fiber)) {
return;
}
pop(didPerformWorkStackCursor, fiber);
pop(contextStackCursor, fiber);
}
function popTopLevelContextObject(fiber) {
pop(didPerformWorkStackCursor, fiber);
pop(contextStackCursor, fiber);
}
function pushTopLevelContextObject(fiber, context, didChange) {
!(contextStackCursor.cursor == null) ? invariant(false, 'Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue.') : void 0;
push(contextStackCursor, context, fiber);
push(didPerformWorkStackCursor, didChange, fiber);
}
function processChildContext(fiber, parentContext) {
var instance = fiber.stateNode;
var childContextTypes = fiber.type.childContextTypes;
// TODO (bvaughn) Replace this behavior with an invariant() in the future.
// It has only been added in Fiber to match the (unintentional) behavior in Stack.
if (typeof instance.getChildContext !== 'function') {
{
var componentName = getComponentName(fiber) || 'Unknown';
if (!warnedAboutMissingGetChildContext[componentName]) {
warnedAboutMissingGetChildContext[componentName] = true;
warning(false, '%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName);
}
}
return parentContext;
}
var childContext = void 0;
{
ReactDebugCurrentFiber.setCurrentPhase('getChildContext');
}
startPhaseTimer(fiber, 'getChildContext');
childContext = instance.getChildContext();
stopPhaseTimer();
{
ReactDebugCurrentFiber.setCurrentPhase(null);
}
for (var contextKey in childContext) {
!(contextKey in childContextTypes) ? invariant(false, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', getComponentName(fiber) || 'Unknown', contextKey) : void 0;
}
{
var name = getComponentName(fiber) || 'Unknown';
checkPropTypes(childContextTypes, childContext, 'child context', name,
// In practice, there is one case in which we won't get a stack. It's when
// somebody calls unstable_renderSubtreeIntoContainer() and we process
// context from the parent component instance. The stack will be missing
// because it's outside of the reconciliation, and so the pointer has not
// been set. This is rare and doesn't matter. We'll also remove that API.
ReactDebugCurrentFiber.getCurrentFiberStackAddendum);
}
return _assign({}, parentContext, childContext);
}
function pushContextProvider(workInProgress) {
if (!isContextProvider(workInProgress)) {
return false;
}
var instance = workInProgress.stateNode;
// We push the context as early as possible to ensure stack integrity.
// If the instance does not exist yet, we will push null at first,
// and replace it on the stack later when invalidating the context.
var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyObject;
// Remember the parent context so we can merge with it later.
// Inherit the parent's did-perform-work value to avoid inadvertently blocking updates.
previousContext = contextStackCursor.current;
push(contextStackCursor, memoizedMergedChildContext, workInProgress);
push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress);
return true;
}
function invalidateContextProvider(workInProgress, didChange) {
var instance = workInProgress.stateNode;
!instance ? invariant(false, 'Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue.') : void 0;
if (didChange) {
// Merge parent and own context.
// Skip this if we're not updating due to sCU.
// This avoids unnecessarily recomputing memoized values.
var mergedContext = processChildContext(workInProgress, previousContext);
instance.__reactInternalMemoizedMergedChildContext = mergedContext;
// Replace the old (or empty) context with the new one.
// It is important to unwind the context in the reverse order.
pop(didPerformWorkStackCursor, workInProgress);
pop(contextStackCursor, workInProgress);
// Now push the new context and mark that it has changed.
push(contextStackCursor, mergedContext, workInProgress);
push(didPerformWorkStackCursor, didChange, workInProgress);
} else {
pop(didPerformWorkStackCursor, workInProgress);
push(didPerformWorkStackCursor, didChange, workInProgress);
}
}
function resetContext() {
previousContext = emptyObject;
contextStackCursor.current = emptyObject;
didPerformWorkStackCursor.current = false;
}
function findCurrentUnmaskedContext(fiber) {
// Currently this is only used with renderSubtreeIntoContainer; not sure if it
// makes sense elsewhere
!(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? invariant(false, 'Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue.') : void 0;
var node = fiber;
while (node.tag !== HostRoot) {
if (isContextProvider(node)) {
return node.stateNode.__reactInternalMemoizedMergedChildContext;
}
var parent = node['return'];
!parent ? invariant(false, 'Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue.') : void 0;
node = parent;
}
return node.stateNode.context;
}
var NoWork = 0; // TODO: Use an opaque type once ESLint et al support the syntax
var Sync = 1;
var Never = 2147483647; // Max int32: Math.pow(2, 31) - 1
var UNIT_SIZE = 10;
var MAGIC_NUMBER_OFFSET = 2;
// 1 unit of expiration time represents 10ms.
function msToExpirationTime(ms) {
// Always add an offset so that we don't clash with the magic number for NoWork.
return (ms / UNIT_SIZE | 0) + MAGIC_NUMBER_OFFSET;
}
function expirationTimeToMs(expirationTime) {
return (expirationTime - MAGIC_NUMBER_OFFSET) * UNIT_SIZE;
}
function ceiling(num, precision) {
return ((num / precision | 0) + 1) * precision;
}
function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) {
return ceiling(currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE);
}
var NoContext = 0;
var AsyncUpdates = 1;
{
var hasBadMapPolyfill = false;
try {
var nonExtensibleObject = Object.preventExtensions({});
/* eslint-disable no-new */
/* eslint-enable no-new */
} catch (e) {
// TODO: Consider warning about bad polyfills
hasBadMapPolyfill = true;
}
}
// A Fiber is work on a Component that needs to be done or was done. There can
// be more than one per component.
{
var debugCounter = 1;
}
function FiberNode(tag, key, internalContextTag) {
// Instance
this.tag = tag;
this.key = key;
this.type = null;
this.stateNode = null;
// Fiber
this['return'] = null;
this.child = null;
this.sibling = null;
this.index = 0;
this.ref = null;
this.pendingProps = null;
this.memoizedProps = null;
this.updateQueue = null;
this.memoizedState = null;
this.internalContextTag = internalContextTag;
// Effects
this.effectTag = NoEffect;
this.nextEffect = null;
this.firstEffect = null;
this.lastEffect = null;
this.expirationTime = NoWork;
this.alternate = null;
{
this._debugID = debugCounter++;
this._debugSource = null;
this._debugOwner = null;
this._debugIsCurrentlyTiming = false;
if (!hasBadMapPolyfill && typeof Object.preventExtensions === 'function') {
Object.preventExtensions(this);
}
}
}
// This is a constructor function, rather than a POJO constructor, still
// please ensure we do the following:
// 1) Nobody should add any instance methods on this. Instance methods can be
// more difficult to predict when they get optimized and they are almost
// never inlined properly in static compilers.
// 2) Nobody should rely on `instanceof Fiber` for type testing. We should
// always know when it is a fiber.
// 3) We might want to experiment with using numeric keys since they are easier
// to optimize in a non-JIT environment.
// 4) We can easily go from a constructor to a createFiber object literal if that
// is faster.
// 5) It should be easy to port this to a C struct and keep a C implementation
// compatible.
var createFiber = function (tag, key, internalContextTag) {
// $FlowFixMe: the shapes are exact here but Flow doesn't like constructors
return new FiberNode(tag, key, internalContextTag);
};
function shouldConstruct(Component) {
return !!(Component.prototype && Component.prototype.isReactComponent);
}
// This is used to create an alternate fiber to do work on.
function createWorkInProgress(current, pendingProps, expirationTime) {
var workInProgress = current.alternate;
if (workInProgress === null) {
// We use a double buffering pooling technique because we know that we'll
// only ever need at most two versions of a tree. We pool the "other" unused
// node that we're free to reuse. This is lazily created to avoid allocating
// extra objects for things that are never updated. It also allow us to
// reclaim the extra memory if needed.
workInProgress = createFiber(current.tag, current.key, current.internalContextTag);
workInProgress.type = current.type;
workInProgress.stateNode = current.stateNode;
{
// DEV-only fields
workInProgress._debugID = current._debugID;
workInProgress._debugSource = current._debugSource;
workInProgress._debugOwner = current._debugOwner;
}
workInProgress.alternate = current;
current.alternate = workInProgress;
} else {
// We already have an alternate.
// Reset the effect tag.
workInProgress.effectTag = NoEffect;
// The effect list is no longer valid.
workInProgress.nextEffect = null;
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
}
workInProgress.expirationTime = expirationTime;
workInProgress.pendingProps = pendingProps;
workInProgress.child = current.child;
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
// These will be overridden during the parent's reconciliation
workInProgress.sibling = current.sibling;
workInProgress.index = current.index;
workInProgress.ref = current.ref;
return workInProgress;
}
function createHostRootFiber() {
var fiber = createFiber(HostRoot, null, NoContext);
return fiber;
}
function createFiberFromElement(element, internalContextTag, expirationTime) {
var owner = null;
{
owner = element._owner;
}
var fiber = void 0;
var type = element.type,
key = element.key;
if (typeof type === 'function') {
fiber = shouldConstruct(type) ? createFiber(ClassComponent, key, internalContextTag) : createFiber(IndeterminateComponent, key, internalContextTag);
fiber.type = type;
fiber.pendingProps = element.props;
} else if (typeof type === 'string') {
fiber = createFiber(HostComponent, key, internalContextTag);
fiber.type = type;
fiber.pendingProps = element.props;
} else if (typeof type === 'object' && type !== null && typeof type.tag === 'number') {
// Currently assumed to be a continuation and therefore is a fiber already.
// TODO: The yield system is currently broken for updates in some cases.
// The reified yield stores a fiber, but we don't know which fiber that is;
// the current or a workInProgress? When the continuation gets rendered here
// we don't know if we can reuse that fiber or if we need to clone it.
// There is probably a clever way to restructure this.
fiber = type;
fiber.pendingProps = element.props;
} else {
var info = '';
{
if (type === undefined || typeof type === 'object' && type !== null && Object.keys(type).length === 0) {
info += ' You likely forgot to export your component from the file ' + "it's defined in, or you might have mixed up default and named imports.";
}
var ownerName = owner ? getComponentName(owner) : null;
if (ownerName) {
info += '\n\nCheck the render method of `' + ownerName + '`.';
}
}
invariant(false, 'Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s', type == null ? type : typeof type, info);
}
{
fiber._debugSource = element._source;
fiber._debugOwner = element._owner;
}
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromFragment(elements, internalContextTag, expirationTime, key) {
var fiber = createFiber(Fragment, key, internalContextTag);
fiber.pendingProps = elements;
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromText(content, internalContextTag, expirationTime) {
var fiber = createFiber(HostText, null, internalContextTag);
fiber.pendingProps = content;
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromHostInstanceForDeletion() {
var fiber = createFiber(HostComponent, null, NoContext);
fiber.type = 'DELETED';
return fiber;
}
function createFiberFromCall(call, internalContextTag, expirationTime) {
var fiber = createFiber(CallComponent, call.key, internalContextTag);
fiber.type = call.handler;
fiber.pendingProps = call;
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromReturn(returnNode, internalContextTag, expirationTime) {
var fiber = createFiber(ReturnComponent, null, internalContextTag);
fiber.expirationTime = expirationTime;
return fiber;
}
function createFiberFromPortal(portal, internalContextTag, expirationTime) {
var fiber = createFiber(HostPortal, portal.key, internalContextTag);
fiber.pendingProps = portal.children || [];
fiber.expirationTime = expirationTime;
fiber.stateNode = {
containerInfo: portal.containerInfo,
pendingChildren: null, // Used by persistent updates
implementation: portal.implementation
};
return fiber;
}
function createFiberRoot(containerInfo, hydrate) {
// Cyclic construction. This cheats the type system right now because
// stateNode is any.
var uninitializedFiber = createHostRootFiber();
var root = {
current: uninitializedFiber,
containerInfo: containerInfo,
pendingChildren: null,
remainingExpirationTime: NoWork,
isReadyForCommit: false,
finishedWork: null,
context: null,
pendingContext: null,
hydrate: hydrate,
nextScheduledRoot: null
};
uninitializedFiber.stateNode = root;
return root;
}
var onCommitFiberRoot = null;
var onCommitFiberUnmount = null;
var hasLoggedError = false;
function catchErrors(fn) {
return function (arg) {
try {
return fn(arg);
} catch (err) {
if (true && !hasLoggedError) {
hasLoggedError = true;
warning(false, 'React DevTools encountered an error: %s', err);
}
}
};
}
function injectInternals(internals) {
if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') {
// No DevTools
return false;
}
var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__;
if (hook.isDisabled) {
// This isn't a real property on the hook, but it can be set to opt out
// of DevTools integration and associated warnings and logs.
// https://github.com/facebook/react/issues/3877
return true;
}
if (!hook.supportsFiber) {
{
warning(false, 'The installed version of React DevTools is too old and will not work ' + 'with the current version of React. Please update React DevTools. ' + 'https://fb.me/react-devtools');
}
// DevTools exists, even though it doesn't support Fiber.
return true;
}
try {
var rendererID = hook.inject(internals);
// We have successfully injected, so now it is safe to set up hooks.
onCommitFiberRoot = catchErrors(function (root) {
return hook.onCommitFiberRoot(rendererID, root);
});
onCommitFiberUnmount = catchErrors(function (fiber) {
return hook.onCommitFiberUnmount(rendererID, fiber);
});
} catch (err) {
// Catch all errors because it is unsafe to throw during initialization.
{
warning(false, 'React DevTools encountered an error: %s.', err);
}
}
// DevTools exists
return true;
}
function onCommitRoot(root) {
if (typeof onCommitFiberRoot === 'function') {
onCommitFiberRoot(root);
}
}
function onCommitUnmount(fiber) {
if (typeof onCommitFiberUnmount === 'function') {
onCommitFiberUnmount(fiber);
}
}
var ReactErrorUtils = {
// Used by Fiber to simulate a try-catch.
_caughtError: null,
_hasCaughtError: false,
// Used by event system to capture/rethrow the first error.
_rethrowError: null,
_hasRethrowError: false,
injection: {
injectErrorUtils: function (injectedErrorUtils) {
!(typeof injectedErrorUtils.invokeGuardedCallback === 'function') ? invariant(false, 'Injected invokeGuardedCallback() must be a function.') : void 0;
invokeGuardedCallback$1 = injectedErrorUtils.invokeGuardedCallback;
}
},
/**
* Call a function while guarding against errors that happens within it.
* Returns an error if it throws, otherwise null.
*
* In production, this is implemented using a try-catch. The reason we don't
* use a try-catch directly is so that we can swap out a different
* implementation in DEV mode.
*
* @param {String} name of the guard to use for logging or debugging
* @param {Function} func The function to invoke
* @param {*} context The context to use when calling the function
* @param {...*} args Arguments for function
*/
invokeGuardedCallback: function (name, func, context, a, b, c, d, e, f) {
invokeGuardedCallback$1.apply(ReactErrorUtils, arguments);
},
/**
* Same as invokeGuardedCallback, but instead of returning an error, it stores
* it in a global so it can be rethrown by `rethrowCaughtError` later.
* TODO: See if _caughtError and _rethrowError can be unified.
*
* @param {String} name of the guard to use for logging or debugging
* @param {Function} func The function to invoke
* @param {*} context The context to use when calling the function
* @param {...*} args Arguments for function
*/
invokeGuardedCallbackAndCatchFirstError: function (name, func, context, a, b, c, d, e, f) {
ReactErrorUtils.invokeGuardedCallback.apply(this, arguments);
if (ReactErrorUtils.hasCaughtError()) {
var error = ReactErrorUtils.clearCaughtError();
if (!ReactErrorUtils._hasRethrowError) {
ReactErrorUtils._hasRethrowError = true;
ReactErrorUtils._rethrowError = error;
}
}
},
/**
* During execution of guarded functions we will capture the first error which
* we will rethrow to be handled by the top level error handler.
*/
rethrowCaughtError: function () {
return rethrowCaughtError.apply(ReactErrorUtils, arguments);
},
hasCaughtError: function () {
return ReactErrorUtils._hasCaughtError;
},
clearCaughtError: function () {
if (ReactErrorUtils._hasCaughtError) {
var error = ReactErrorUtils._caughtError;
ReactErrorUtils._caughtError = null;
ReactErrorUtils._hasCaughtError = false;
return error;
} else {
invariant(false, 'clearCaughtError was called but no error was captured. This error is likely caused by a bug in React. Please file an issue.');
}
}
};
var invokeGuardedCallback$1 = function (name, func, context, a, b, c, d, e, f) {
ReactErrorUtils._hasCaughtError = false;
ReactErrorUtils._caughtError = null;
var funcArgs = Array.prototype.slice.call(arguments, 3);
try {
func.apply(context, funcArgs);
} catch (error) {
ReactErrorUtils._caughtError = error;
ReactErrorUtils._hasCaughtError = true;
}
};
{
// In DEV mode, we swap out invokeGuardedCallback for a special version
// that plays more nicely with the browser's DevTools. The idea is to preserve
// "Pause on exceptions" behavior. Because React wraps all user-provided
// functions in invokeGuardedCallback, and the production version of
// invokeGuardedCallback uses a try-catch, all user exceptions are treated
// like caught exceptions, and the DevTools won't pause unless the developer
// takes the extra step of enabling pause on caught exceptions. This is
// untintuitive, though, because even though React has caught the error, from
// the developer's perspective, the error is uncaught.
//
// To preserve the expected "Pause on exceptions" behavior, we don't use a
// try-catch in DEV. Instead, we synchronously dispatch a fake event to a fake
// DOM node, and call the user-provided callback from inside an event handler
// for that fake event. If the callback throws, the error is "captured" using
// a global event handler. But because the error happens in a different
// event loop context, it does not interrupt the normal program flow.
// Effectively, this gives us try-catch behavior without actually using
// try-catch. Neat!
// Check that the browser supports the APIs we need to implement our special
// DEV version of invokeGuardedCallback
if (typeof window !== 'undefined' && typeof window.dispatchEvent === 'function' && typeof document !== 'undefined' && typeof document.createEvent === 'function') {
var fakeNode = document.createElement('react');
var invokeGuardedCallbackDev = function (name, func, context, a, b, c, d, e, f) {
// Keeps track of whether the user-provided callback threw an error. We
// set this to true at the beginning, then set it to false right after
// calling the function. If the function errors, `didError` will never be
// set to false. This strategy works even if the browser is flaky and
// fails to call our global error handler, because it doesn't rely on
// the error event at all.
var didError = true;
// Create an event handler for our fake event. We will synchronously
// dispatch our fake event using `dispatchEvent`. Inside the handler, we
// call the user-provided callback.
var funcArgs = Array.prototype.slice.call(arguments, 3);
function callCallback() {
// We immediately remove the callback from event listeners so that
// nested `invokeGuardedCallback` calls do not clash. Otherwise, a
// nested call would trigger the fake event handlers of any call higher
// in the stack.
fakeNode.removeEventListener(evtType, callCallback, false);
func.apply(context, funcArgs);
didError = false;
}
// Create a global error event handler. We use this to capture the value
// that was thrown. It's possible that this error handler will fire more
// than once; for example, if non-React code also calls `dispatchEvent`
// and a handler for that event throws. We should be resilient to most of
// those cases. Even if our error event handler fires more than once, the
// last error event is always used. If the callback actually does error,
// we know that the last error event is the correct one, because it's not
// possible for anything else to have happened in between our callback
// erroring and the code that follows the `dispatchEvent` call below. If
// the callback doesn't error, but the error event was fired, we know to
// ignore it because `didError` will be false, as described above.
var error = void 0;
// Use this to track whether the error event is ever called.
var didSetError = false;
var isCrossOriginError = false;
function onError(event) {
error = event.error;
didSetError = true;
if (error === null && event.colno === 0 && event.lineno === 0) {
isCrossOriginError = true;
}
}
// Create a fake event type.
var evtType = 'react-' + (name ? name : 'invokeguardedcallback');
// Attach our event handlers
window.addEventListener('error', onError);
fakeNode.addEventListener(evtType, callCallback, false);
// Synchronously dispatch our fake event. If the user-provided function
// errors, it will trigger our global error handler.
var evt = document.createEvent('Event');
evt.initEvent(evtType, false, false);
fakeNode.dispatchEvent(evt);
if (didError) {
if (!didSetError) {
// The callback errored, but the error event never fired.
error = new Error('An error was thrown inside one of your components, but React ' + "doesn't know what it was. This is likely due to browser " + 'flakiness. React does its best to preserve the "Pause on ' + 'exceptions" behavior of the DevTools, which requires some ' + "DEV-mode only tricks. It's possible that these don't work in " + 'your browser. Try triggering the error in production mode, ' + 'or switching to a modern browser. If you suspect that this is ' + 'actually an issue with React, please file an issue.');
} else if (isCrossOriginError) {
error = new Error("A cross-origin error was thrown. React doesn't have access to " + 'the actual error object in development. ' + 'See https://fb.me/react-crossorigin-error for more information.');
}
ReactErrorUtils._hasCaughtError = true;
ReactErrorUtils._caughtError = error;
} else {
ReactErrorUtils._hasCaughtError = false;
ReactErrorUtils._caughtError = null;
}
// Remove our event listeners
window.removeEventListener('error', onError);
};
invokeGuardedCallback$1 = invokeGuardedCallbackDev;
}
}
var rethrowCaughtError = function () {
if (ReactErrorUtils._hasRethrowError) {
var error = ReactErrorUtils._rethrowError;
ReactErrorUtils._rethrowError = null;
ReactErrorUtils._hasRethrowError = false;
throw error;
}
};
{
var didWarnUpdateInsideUpdate = false;
}
// Callbacks are not validated until invocation
// Singly linked-list of updates. When an update is scheduled, it is added to
// the queue of the current fiber and the work-in-progress fiber. The two queues
// are separate but they share a persistent structure.
//
// During reconciliation, updates are removed from the work-in-progress fiber,
// but they remain on the current fiber. That ensures that if a work-in-progress
// is aborted, the aborted updates are recovered by cloning from current.
//
// The work-in-progress queue is always a subset of the current queue.
//
// When the tree is committed, the work-in-progress becomes the current.
function createUpdateQueue(baseState) {
var queue = {
baseState: baseState,
expirationTime: NoWork,
first: null,
last: null,
callbackList: null,
hasForceUpdate: false,
isInitialized: false
};
{
queue.isProcessing = false;
}
return queue;
}
function insertUpdateIntoQueue(queue, update) {
// Append the update to the end of the list.
if (queue.last === null) {
// Queue is empty
queue.first = queue.last = update;
} else {
queue.last.next = update;
queue.last = update;
}
if (queue.expirationTime === NoWork || queue.expirationTime > update.expirationTime) {
queue.expirationTime = update.expirationTime;
}
}
function insertUpdateIntoFiber(fiber, update) {
// We'll have at least one and at most two distinct update queues.
var alternateFiber = fiber.alternate;
var queue1 = fiber.updateQueue;
if (queue1 === null) {
// TODO: We don't know what the base state will be until we begin work.
// It depends on which fiber is the next current. Initialize with an empty
// base state, then set to the memoizedState when rendering. Not super
// happy with this approach.
queue1 = fiber.updateQueue = createUpdateQueue(null);
}
var queue2 = void 0;
if (alternateFiber !== null) {
queue2 = alternateFiber.updateQueue;
if (queue2 === null) {
queue2 = alternateFiber.updateQueue = createUpdateQueue(null);
}
} else {
queue2 = null;
}
queue2 = queue2 !== queue1 ? queue2 : null;
// Warn if an update is scheduled from inside an updater function.
{
if ((queue1.isProcessing || queue2 !== null && queue2.isProcessing) && !didWarnUpdateInsideUpdate) {
warning(false, 'An update (setState, replaceState, or forceUpdate) was scheduled ' + 'from inside an update function. Update functions should be pure, ' + 'with zero side-effects. Consider using componentDidUpdate or a ' + 'callback.');
didWarnUpdateInsideUpdate = true;
}
}
// If there's only one queue, add the update to that queue and exit.
if (queue2 === null) {
insertUpdateIntoQueue(queue1, update);
return;
}
// If either queue is empty, we need to add to both queues.
if (queue1.last === null || queue2.last === null) {
insertUpdateIntoQueue(queue1, update);
insertUpdateIntoQueue(queue2, update);
return;
}
// If both lists are not empty, the last update is the same for both lists
// because of structural sharing. So, we should only append to one of
// the lists.
insertUpdateIntoQueue(queue1, update);
// But we still need to update the `last` pointer of queue2.
queue2.last = update;
}
function getUpdateExpirationTime(fiber) {
if (fiber.tag !== ClassComponent && fiber.tag !== HostRoot) {
return NoWork;
}
var updateQueue = fiber.updateQueue;
if (updateQueue === null) {
return NoWork;
}
return updateQueue.expirationTime;
}
function getStateFromUpdate(update, instance, prevState, props) {
var partialState = update.partialState;
if (typeof partialState === 'function') {
var updateFn = partialState;
// Invoke setState callback an extra time to help detect side-effects.
if (debugRenderPhaseSideEffects) {
updateFn.call(instance, prevState, props);
}
return updateFn.call(instance, prevState, props);
} else {
return partialState;
}
}
function processUpdateQueue(current, workInProgress, queue, instance, props, renderExpirationTime) {
if (current !== null && current.updateQueue === queue) {
// We need to create a work-in-progress queue, by cloning the current queue.
var currentQueue = queue;
queue = workInProgress.updateQueue = {
baseState: currentQueue.baseState,
expirationTime: currentQueue.expirationTime,
first: currentQueue.first,
last: currentQueue.last,
isInitialized: currentQueue.isInitialized,
// These fields are no longer valid because they were already committed.
// Reset them.
callbackList: null,
hasForceUpdate: false
};
}
{
// Set this flag so we can warn if setState is called inside the update
// function of another setState.
queue.isProcessing = true;
}
// Reset the remaining expiration time. If we skip over any updates, we'll
// increase this accordingly.
queue.expirationTime = NoWork;
// TODO: We don't know what the base state will be until we begin work.
// It depends on which fiber is the next current. Initialize with an empty
// base state, then set to the memoizedState when rendering. Not super
// happy with this approach.
var state = void 0;
if (queue.isInitialized) {
state = queue.baseState;
} else {
state = queue.baseState = workInProgress.memoizedState;
queue.isInitialized = true;
}
var dontMutatePrevState = true;
var update = queue.first;
var didSkip = false;
while (update !== null) {
var updateExpirationTime = update.expirationTime;
if (updateExpirationTime > renderExpirationTime) {
// This update does not have sufficient priority. Skip it.
var remainingExpirationTime = queue.expirationTime;
if (remainingExpirationTime === NoWork || remainingExpirationTime > updateExpirationTime) {
// Update the remaining expiration time.
queue.expirationTime = updateExpirationTime;
}
if (!didSkip) {
didSkip = true;
queue.baseState = state;
}
// Continue to the next update.
update = update.next;
continue;
}
// This update does have sufficient priority.
// If no previous updates were skipped, drop this update from the queue by
// advancing the head of the list.
if (!didSkip) {
queue.first = update.next;
if (queue.first === null) {
queue.last = null;
}
}
// Process the update
var _partialState = void 0;
if (update.isReplace) {
state = getStateFromUpdate(update, instance, state, props);
dontMutatePrevState = true;
} else {
_partialState = getStateFromUpdate(update, instance, state, props);
if (_partialState) {
if (dontMutatePrevState) {
// $FlowFixMe: Idk how to type this properly.
state = _assign({}, state, _partialState);
} else {
state = _assign(state, _partialState);
}
dontMutatePrevState = false;
}
}
if (update.isForced) {
queue.hasForceUpdate = true;
}
if (update.callback !== null) {
// Append to list of callbacks.
var _callbackList = queue.callbackList;
if (_callbackList === null) {
_callbackList = queue.callbackList = [];
}
_callbackList.push(update);
}
update = update.next;
}
if (queue.callbackList !== null) {
workInProgress.effectTag |= Callback;
} else if (queue.first === null && !queue.hasForceUpdate) {
// The queue is empty. We can reset it.
workInProgress.updateQueue = null;
}
if (!didSkip) {
didSkip = true;
queue.baseState = state;
}
{
// No longer processing.
queue.isProcessing = false;
}
return state;
}
function commitCallbacks(queue, context) {
var callbackList = queue.callbackList;
if (callbackList === null) {
return;
}
// Set the list to null to make sure they don't get called more than once.
queue.callbackList = null;
for (var i = 0; i < callbackList.length; i++) {
var update = callbackList[i];
var _callback = update.callback;
// This update might be processed again. Clear the callback so it's only
// called once.
update.callback = null;
!(typeof _callback === 'function') ? invariant(false, 'Invalid argument passed as callback. Expected a function. Instead received: %s', _callback) : void 0;
_callback.call(context);
}
}
var fakeInternalInstance = {};
var isArray = Array.isArray;
{
var didWarnAboutStateAssignmentForComponent = {};
var warnOnInvalidCallback = function (callback, callerName) {
warning(callback === null || typeof callback === 'function', '%s(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callerName, callback);
};
// This is so gross but it's at least non-critical and can be removed if
// it causes problems. This is meant to give a nicer error message for
// ReactDOM15.unstable_renderSubtreeIntoContainer(reactDOM16Component,
// ...)) which otherwise throws a "_processChildContext is not a function"
// exception.
Object.defineProperty(fakeInternalInstance, '_processChildContext', {
enumerable: false,
value: function () {
invariant(false, '_processChildContext is not available in React 16+. This likely means you have multiple copies of React and are attempting to nest a React 15 tree inside a React 16 tree using unstable_renderSubtreeIntoContainer, which isn\'t supported. Try to make sure you have only one copy of React (and ideally, switch to ReactDOM.createPortal).');
}
});
Object.freeze(fakeInternalInstance);
}
var ReactFiberClassComponent = function (scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState) {
// Class component state updater
var updater = {
isMounted: isMounted,
enqueueSetState: function (instance, partialState, callback) {
var fiber = get(instance);
callback = callback === undefined ? null : callback;
{
warnOnInvalidCallback(callback, 'setState');
}
var expirationTime = computeExpirationForFiber(fiber);
var update = {
expirationTime: expirationTime,
partialState: partialState,
callback: callback,
isReplace: false,
isForced: false,
nextCallback: null,
next: null
};
insertUpdateIntoFiber(fiber, update);
scheduleWork(fiber, expirationTime);
},
enqueueReplaceState: function (instance, state, callback) {
var fiber = get(instance);
callback = callback === undefined ? null : callback;
{
warnOnInvalidCallback(callback, 'replaceState');
}
var expirationTime = computeExpirationForFiber(fiber);
var update = {
expirationTime: expirationTime,
partialState: state,
callback: callback,
isReplace: true,
isForced: false,
nextCallback: null,
next: null
};
insertUpdateIntoFiber(fiber, update);
scheduleWork(fiber, expirationTime);
},
enqueueForceUpdate: function (instance, callback) {
var fiber = get(instance);
callback = callback === undefined ? null : callback;
{
warnOnInvalidCallback(callback, 'forceUpdate');
}
var expirationTime = computeExpirationForFiber(fiber);
var update = {
expirationTime: expirationTime,
partialState: null,
callback: callback,
isReplace: false,
isForced: true,
nextCallback: null,
next: null
};
insertUpdateIntoFiber(fiber, update);
scheduleWork(fiber, expirationTime);
}
};
function checkShouldComponentUpdate(workInProgress, oldProps, newProps, oldState, newState, newContext) {
if (oldProps === null || workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate) {
// If the workInProgress already has an Update effect, return true
return true;
}
var instance = workInProgress.stateNode;
var type = workInProgress.type;
if (typeof instance.shouldComponentUpdate === 'function') {
startPhaseTimer(workInProgress, 'shouldComponentUpdate');
var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, newContext);
stopPhaseTimer();
// Simulate an async bailout/interruption by invoking lifecycle twice.
if (debugRenderPhaseSideEffects) {
instance.shouldComponentUpdate(newProps, newState, newContext);
}
{
warning(shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentName(workInProgress) || 'Unknown');
}
return shouldUpdate;
}
if (type.prototype && type.prototype.isPureReactComponent) {
return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState);
}
return true;
}
function checkClassInstance(workInProgress) {
var instance = workInProgress.stateNode;
var type = workInProgress.type;
{
var name = getComponentName(workInProgress);
var renderPresent = instance.render;
if (!renderPresent) {
if (type.prototype && typeof type.prototype.render === 'function') {
warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name);
} else {
warning(false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name);
}
}
var noGetInitialStateOnES6 = !instance.getInitialState || instance.getInitialState.isReactClassApproved || instance.state;
warning(noGetInitialStateOnES6, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', name);
var noGetDefaultPropsOnES6 = !instance.getDefaultProps || instance.getDefaultProps.isReactClassApproved;
warning(noGetDefaultPropsOnES6, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', name);
var noInstancePropTypes = !instance.propTypes;
warning(noInstancePropTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name);
var noInstanceContextTypes = !instance.contextTypes;
warning(noInstanceContextTypes, 'contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name);
var noComponentShouldUpdate = typeof instance.componentShouldUpdate !== 'function';
warning(noComponentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', name);
if (type.prototype && type.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined') {
warning(false, '%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentName(workInProgress) || 'A pure component');
}
var noComponentDidUnmount = typeof instance.componentDidUnmount !== 'function';
warning(noComponentDidUnmount, '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name);
var noComponentDidReceiveProps = typeof instance.componentDidReceiveProps !== 'function';
warning(noComponentDidReceiveProps, '%s has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', name);
var noComponentWillRecieveProps = typeof instance.componentWillRecieveProps !== 'function';
warning(noComponentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name);
var hasMutatedProps = instance.props !== workInProgress.pendingProps;
warning(instance.props === undefined || !hasMutatedProps, '%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name, name);
var noInstanceDefaultProps = !instance.defaultProps;
warning(noInstanceDefaultProps, 'Setting defaultProps as an instance property on %s is not supported and will be ignored.' + ' Instead, define defaultProps as a static property on %s.', name, name);
}
var state = instance.state;
if (state && (typeof state !== 'object' || isArray(state))) {
warning(false, '%s.state: must be set to an object or null', getComponentName(workInProgress));
}
if (typeof instance.getChildContext === 'function') {
warning(typeof workInProgress.type.childContextTypes === 'object', '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', getComponentName(workInProgress));
}
}
function resetInputPointers(workInProgress, instance) {
instance.props = workInProgress.memoizedProps;
instance.state = workInProgress.memoizedState;
}
function adoptClassInstance(workInProgress, instance) {
instance.updater = updater;
workInProgress.stateNode = instance;
// The instance needs access to the fiber so that it can schedule updates
set(instance, workInProgress);
{
instance._reactInternalInstance = fakeInternalInstance;
}
}
function constructClassInstance(workInProgress, props) {
var ctor = workInProgress.type;
var unmaskedContext = getUnmaskedContext(workInProgress);
var needsContext = isContextConsumer(workInProgress);
var context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject;
var instance = new ctor(props, context);
adoptClassInstance(workInProgress, instance);
// Cache unmasked context so we can avoid recreating masked context unless necessary.
// ReactFiberContext usually updates this cache but can't for newly-created instances.
if (needsContext) {
cacheContext(workInProgress, unmaskedContext, context);
}
return instance;
}
function callComponentWillMount(workInProgress, instance) {
startPhaseTimer(workInProgress, 'componentWillMount');
var oldState = instance.state;
instance.componentWillMount();
stopPhaseTimer();
// Simulate an async bailout/interruption by invoking lifecycle twice.
if (debugRenderPhaseSideEffects) {
instance.componentWillMount();
}
if (oldState !== instance.state) {
{
warning(false, '%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName(workInProgress));
}
updater.enqueueReplaceState(instance, instance.state, null);
}
}
function callComponentWillReceiveProps(workInProgress, instance, newProps, newContext) {
startPhaseTimer(workInProgress, 'componentWillReceiveProps');
var oldState = instance.state;
instance.componentWillReceiveProps(newProps, newContext);
stopPhaseTimer();
// Simulate an async bailout/interruption by invoking lifecycle twice.
if (debugRenderPhaseSideEffects) {
instance.componentWillReceiveProps(newProps, newContext);
}
if (instance.state !== oldState) {
{
var componentName = getComponentName(workInProgress) || 'Component';
if (!didWarnAboutStateAssignmentForComponent[componentName]) {
warning(false, '%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', componentName);
didWarnAboutStateAssignmentForComponent[componentName] = true;
}
}
updater.enqueueReplaceState(instance, instance.state, null);
}
}
// Invokes the mount life-cycles on a previously never rendered instance.
function mountClassInstance(workInProgress, renderExpirationTime) {
var current = workInProgress.alternate;
{
checkClassInstance(workInProgress);
}
var instance = workInProgress.stateNode;
var state = instance.state || null;
var props = workInProgress.pendingProps;
!props ? invariant(false, 'There must be pending props for an initial mount. This error is likely caused by a bug in React. Please file an issue.') : void 0;
var unmaskedContext = getUnmaskedContext(workInProgress);
instance.props = props;
instance.state = workInProgress.memoizedState = state;
instance.refs = emptyObject;
instance.context = getMaskedContext(workInProgress, unmaskedContext);
if (enableAsyncSubtreeAPI && workInProgress.type != null && workInProgress.type.prototype != null && workInProgress.type.prototype.unstable_isAsyncReactComponent === true) {
workInProgress.internalContextTag |= AsyncUpdates;
}
if (typeof instance.componentWillMount === 'function') {
callComponentWillMount(workInProgress, instance);
// If we had additional state updates during this life-cycle, let's
// process them now.
var updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
instance.state = processUpdateQueue(current, workInProgress, updateQueue, instance, props, renderExpirationTime);
}
}
if (typeof instance.componentDidMount === 'function') {
workInProgress.effectTag |= Update;
}
}
// Called on a preexisting class instance. Returns false if a resumed render
// could be reused.
// function resumeMountClassInstance(
// workInProgress: Fiber,
// priorityLevel: PriorityLevel,
// ): boolean {
// const instance = workInProgress.stateNode;
// resetInputPointers(workInProgress, instance);
// let newState = workInProgress.memoizedState;
// let newProps = workInProgress.pendingProps;
// if (!newProps) {
// // If there isn't any new props, then we'll reuse the memoized props.
// // This could be from already completed work.
// newProps = workInProgress.memoizedProps;
// invariant(
// newProps != null,
// 'There should always be pending or memoized props. This error is ' +
// 'likely caused by a bug in React. Please file an issue.',
// );
// }
// const newUnmaskedContext = getUnmaskedContext(workInProgress);
// const newContext = getMaskedContext(workInProgress, newUnmaskedContext);
// const oldContext = instance.context;
// const oldProps = workInProgress.memoizedProps;
// if (
// typeof instance.componentWillReceiveProps === 'function' &&
// (oldProps !== newProps || oldContext !== newContext)
// ) {
// callComponentWillReceiveProps(
// workInProgress,
// instance,
// newProps,
// newContext,
// );
// }
// // Process the update queue before calling shouldComponentUpdate
// const updateQueue = workInProgress.updateQueue;
// if (updateQueue !== null) {
// newState = processUpdateQueue(
// workInProgress,
// updateQueue,
// instance,
// newState,
// newProps,
// priorityLevel,
// );
// }
// // TODO: Should we deal with a setState that happened after the last
// // componentWillMount and before this componentWillMount? Probably
// // unsupported anyway.
// if (
// !checkShouldComponentUpdate(
// workInProgress,
// workInProgress.memoizedProps,
// newProps,
// workInProgress.memoizedState,
// newState,
// newContext,
// )
// ) {
// // Update the existing instance's state, props, and context pointers even
// // though we're bailing out.
// instance.props = newProps;
// instance.state = newState;
// instance.context = newContext;
// return false;
// }
// // Update the input pointers now so that they are correct when we call
// // componentWillMount
// instance.props = newProps;
// instance.state = newState;
// instance.context = newContext;
// if (typeof instance.componentWillMount === 'function') {
// callComponentWillMount(workInProgress, instance);
// // componentWillMount may have called setState. Process the update queue.
// const newUpdateQueue = workInProgress.updateQueue;
// if (newUpdateQueue !== null) {
// newState = processUpdateQueue(
// workInProgress,
// newUpdateQueue,
// instance,
// newState,
// newProps,
// priorityLevel,
// );
// }
// }
// if (typeof instance.componentDidMount === 'function') {
// workInProgress.effectTag |= Update;
// }
// instance.state = newState;
// return true;
// }
// Invokes the update life-cycles and returns false if it shouldn't rerender.
function updateClassInstance(current, workInProgress, renderExpirationTime) {
var instance = workInProgress.stateNode;
resetInputPointers(workInProgress, instance);
var oldProps = workInProgress.memoizedProps;
var newProps = workInProgress.pendingProps;
if (!newProps) {
// If there aren't any new props, then we'll reuse the memoized props.
// This could be from already completed work.
newProps = oldProps;
!(newProps != null) ? invariant(false, 'There should always be pending or memoized props. This error is likely caused by a bug in React. Please file an issue.') : void 0;
}
var oldContext = instance.context;
var newUnmaskedContext = getUnmaskedContext(workInProgress);
var newContext = getMaskedContext(workInProgress, newUnmaskedContext);
// Note: During these life-cycles, instance.props/instance.state are what
// ever the previously attempted to render - not the "current". However,
// during componentDidUpdate we pass the "current" props.
if (typeof instance.componentWillReceiveProps === 'function' && (oldProps !== newProps || oldContext !== newContext)) {
callComponentWillReceiveProps(workInProgress, instance, newProps, newContext);
}
// Compute the next state using the memoized state and the update queue.
var oldState = workInProgress.memoizedState;
// TODO: Previous state can be null.
var newState = void 0;
if (workInProgress.updateQueue !== null) {
newState = processUpdateQueue(current, workInProgress, workInProgress.updateQueue, instance, newProps, renderExpirationTime);
} else {
newState = oldState;
}
if (oldProps === newProps && oldState === newState && !hasContextChanged() && !(workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate)) {
// If an update was already in progress, we should schedule an Update
// effect even though we're bailing out, so that cWU/cDU are called.
if (typeof instance.componentDidUpdate === 'function') {
if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {
workInProgress.effectTag |= Update;
}
}
return false;
}
var shouldUpdate = checkShouldComponentUpdate(workInProgress, oldProps, newProps, oldState, newState, newContext);
if (shouldUpdate) {
if (typeof instance.componentWillUpdate === 'function') {
startPhaseTimer(workInProgress, 'componentWillUpdate');
instance.componentWillUpdate(newProps, newState, newContext);
stopPhaseTimer();
// Simulate an async bailout/interruption by invoking lifecycle twice.
if (debugRenderPhaseSideEffects) {
instance.componentWillUpdate(newProps, newState, newContext);
}
}
if (typeof instance.componentDidUpdate === 'function') {
workInProgress.effectTag |= Update;
}
} else {
// If an update was already in progress, we should schedule an Update
// effect even though we're bailing out, so that cWU/cDU are called.
if (typeof instance.componentDidUpdate === 'function') {
if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) {
workInProgress.effectTag |= Update;
}
}
// If shouldComponentUpdate returned false, we should still update the
// memoized props/state to indicate that this work can be reused.
memoizeProps(workInProgress, newProps);
memoizeState(workInProgress, newState);
}
// Update the existing instance's state, props, and context pointers even
// if shouldComponentUpdate returns false.
instance.props = newProps;
instance.state = newState;
instance.context = newContext;
return shouldUpdate;
}
return {
adoptClassInstance: adoptClassInstance,
constructClassInstance: constructClassInstance,
mountClassInstance: mountClassInstance,
// resumeMountClassInstance,
updateClassInstance: updateClassInstance
};
};
// The Symbol used to tag the ReactElement-like types. If there is no native Symbol
// nor polyfill, then a plain number is used for performance.
var hasSymbol = typeof Symbol === 'function' && Symbol['for'];
var REACT_ELEMENT_TYPE = hasSymbol ? Symbol['for']('react.element') : 0xeac7;
var REACT_CALL_TYPE = hasSymbol ? Symbol['for']('react.call') : 0xeac8;
var REACT_RETURN_TYPE = hasSymbol ? Symbol['for']('react.return') : 0xeac9;
var REACT_PORTAL_TYPE = hasSymbol ? Symbol['for']('react.portal') : 0xeaca;
var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol['for']('react.fragment') : 0xeacb;
var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
var FAUX_ITERATOR_SYMBOL = '@@iterator';
function getIteratorFn(maybeIterable) {
if (maybeIterable === null || typeof maybeIterable === 'undefined') {
return null;
}
var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL];
if (typeof maybeIterator === 'function') {
return maybeIterator;
}
return null;
}
var getCurrentFiberStackAddendum$1 = ReactDebugCurrentFiber.getCurrentFiberStackAddendum;
{
var didWarnAboutMaps = false;
/**
* Warn if there's no key explicitly set on dynamic arrays of children or
* object keys are not valid. This allows us to keep track of children between
* updates.
*/
var ownerHasKeyUseWarning = {};
var ownerHasFunctionTypeWarning = {};
var warnForMissingKey = function (child) {
if (child === null || typeof child !== 'object') {
return;
}
if (!child._store || child._store.validated || child.key != null) {
return;
}
!(typeof child._store === 'object') ? invariant(false, 'React Component in warnForMissingKey should have a _store. This error is likely caused by a bug in React. Please file an issue.') : void 0;
child._store.validated = true;
var currentComponentErrorInfo = 'Each child in an array or iterator should have a unique ' + '"key" prop. See https://fb.me/react-warning-keys for ' + 'more information.' + (getCurrentFiberStackAddendum$1() || '');
if (ownerHasKeyUseWarning[currentComponentErrorInfo]) {
return;
}
ownerHasKeyUseWarning[currentComponentErrorInfo] = true;
warning(false, 'Each child in an array or iterator should have a unique ' + '"key" prop. See https://fb.me/react-warning-keys for ' + 'more information.%s', getCurrentFiberStackAddendum$1());
};
}
var isArray$1 = Array.isArray;
function coerceRef(current, element) {
var mixedRef = element.ref;
if (mixedRef !== null && typeof mixedRef !== 'function') {
if (element._owner) {
var owner = element._owner;
var inst = void 0;
if (owner) {
var ownerFiber = owner;
!(ownerFiber.tag === ClassComponent) ? invariant(false, 'Stateless function components cannot have refs.') : void 0;
inst = ownerFiber.stateNode;
}
!inst ? invariant(false, 'Missing owner for string ref %s. This error is likely caused by a bug in React. Please file an issue.', mixedRef) : void 0;
var stringRef = '' + mixedRef;
// Check if previous string ref matches new string ref
if (current !== null && current.ref !== null && current.ref._stringRef === stringRef) {
return current.ref;
}
var ref = function (value) {
var refs = inst.refs === emptyObject ? inst.refs = {} : inst.refs;
if (value === null) {
delete refs[stringRef];
} else {
refs[stringRef] = value;
}
};
ref._stringRef = stringRef;
return ref;
} else {
!(typeof mixedRef === 'string') ? invariant(false, 'Expected ref to be a function or a string.') : void 0;
!element._owner ? invariant(false, 'Element ref was specified as a string (%s) but no owner was set. You may have multiple copies of React loaded. (details: https://fb.me/react-refs-must-have-owner).', mixedRef) : void 0;
}
}
return mixedRef;
}
function throwOnInvalidObjectType(returnFiber, newChild) {
if (returnFiber.type !== 'textarea') {
var addendum = '';
{
addendum = ' If you meant to render a collection of children, use an array ' + 'instead.' + (getCurrentFiberStackAddendum$1() || '');
}
invariant(false, 'Objects are not valid as a React child (found: %s).%s', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum);
}
}
function warnOnFunctionType() {
var currentComponentErrorInfo = 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of from render. ' + 'Or maybe you meant to call this function rather than return it.' + (getCurrentFiberStackAddendum$1() || '');
if (ownerHasFunctionTypeWarning[currentComponentErrorInfo]) {
return;
}
ownerHasFunctionTypeWarning[currentComponentErrorInfo] = true;
warning(false, 'Functions are not valid as a React child. This may happen if ' + 'you return a Component instead of from render. ' + 'Or maybe you meant to call this function rather than return it.%s', getCurrentFiberStackAddendum$1() || '');
}
// This wrapper function exists because I expect to clone the code in each path
// to be able to optimize each path individually by branching early. This needs
// a compiler or we can do it manually. Helpers that don't need this branching
// live outside of this function.
function ChildReconciler(shouldTrackSideEffects) {
function deleteChild(returnFiber, childToDelete) {
if (!shouldTrackSideEffects) {
// Noop.
return;
}
// Deletions are added in reversed order so we add it to the front.
// At this point, the return fiber's effect list is empty except for
// deletions, so we can just append the deletion to the list. The remaining
// effects aren't added until the complete phase. Once we implement
// resuming, this may not be true.
var last = returnFiber.lastEffect;
if (last !== null) {
last.nextEffect = childToDelete;
returnFiber.lastEffect = childToDelete;
} else {
returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
}
childToDelete.nextEffect = null;
childToDelete.effectTag = Deletion;
}
function deleteRemainingChildren(returnFiber, currentFirstChild) {
if (!shouldTrackSideEffects) {
// Noop.
return null;
}
// TODO: For the shouldClone case, this could be micro-optimized a bit by
// assuming that after the first child we've already added everything.
var childToDelete = currentFirstChild;
while (childToDelete !== null) {
deleteChild(returnFiber, childToDelete);
childToDelete = childToDelete.sibling;
}
return null;
}
function mapRemainingChildren(returnFiber, currentFirstChild) {
// Add the remaining children to a temporary map so that we can find them by
// keys quickly. Implicit (null) keys get added to this set with their index
var existingChildren = new Map();
var existingChild = currentFirstChild;
while (existingChild !== null) {
if (existingChild.key !== null) {
existingChildren.set(existingChild.key, existingChild);
} else {
existingChildren.set(existingChild.index, existingChild);
}
existingChild = existingChild.sibling;
}
return existingChildren;
}
function useFiber(fiber, pendingProps, expirationTime) {
// We currently set sibling to null and index to 0 here because it is easy
// to forget to do before returning it. E.g. for the single child case.
var clone = createWorkInProgress(fiber, pendingProps, expirationTime);
clone.index = 0;
clone.sibling = null;
return clone;
}
function placeChild(newFiber, lastPlacedIndex, newIndex) {
newFiber.index = newIndex;
if (!shouldTrackSideEffects) {
// Noop.
return lastPlacedIndex;
}
var current = newFiber.alternate;
if (current !== null) {
var oldIndex = current.index;
if (oldIndex < lastPlacedIndex) {
// This is a move.
newFiber.effectTag = Placement;
return lastPlacedIndex;
} else {
// This item can stay in place.
return oldIndex;
}
} else {
// This is an insertion.
newFiber.effectTag = Placement;
return lastPlacedIndex;
}
}
function placeSingleChild(newFiber) {
// This is simpler for the single child case. We only need to do a
// placement for inserting new children.
if (shouldTrackSideEffects && newFiber.alternate === null) {
newFiber.effectTag = Placement;
}
return newFiber;
}
function updateTextNode(returnFiber, current, textContent, expirationTime) {
if (current === null || current.tag !== HostText) {
// Insert
var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime);
created['return'] = returnFiber;
return created;
} else {
// Update
var existing = useFiber(current, textContent, expirationTime);
existing['return'] = returnFiber;
return existing;
}
}
function updateElement(returnFiber, current, element, expirationTime) {
if (current !== null && current.type === element.type) {
// Move based on index
var existing = useFiber(current, element.props, expirationTime);
existing.ref = coerceRef(current, element);
existing['return'] = returnFiber;
{
existing._debugSource = element._source;
existing._debugOwner = element._owner;
}
return existing;
} else {
// Insert
var created = createFiberFromElement(element, returnFiber.internalContextTag, expirationTime);
created.ref = coerceRef(current, element);
created['return'] = returnFiber;
return created;
}
}
function updateCall(returnFiber, current, call, expirationTime) {
// TODO: Should this also compare handler to determine whether to reuse?
if (current === null || current.tag !== CallComponent) {
// Insert
var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime);
created['return'] = returnFiber;
return created;
} else {
// Move based on index
var existing = useFiber(current, call, expirationTime);
existing['return'] = returnFiber;
return existing;
}
}
function updateReturn(returnFiber, current, returnNode, expirationTime) {
if (current === null || current.tag !== ReturnComponent) {
// Insert
var created = createFiberFromReturn(returnNode, returnFiber.internalContextTag, expirationTime);
created.type = returnNode.value;
created['return'] = returnFiber;
return created;
} else {
// Move based on index
var existing = useFiber(current, null, expirationTime);
existing.type = returnNode.value;
existing['return'] = returnFiber;
return existing;
}
}
function updatePortal(returnFiber, current, portal, expirationTime) {
if (current === null || current.tag !== HostPortal || current.stateNode.containerInfo !== portal.containerInfo || current.stateNode.implementation !== portal.implementation) {
// Insert
var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime);
created['return'] = returnFiber;
return created;
} else {
// Update
var existing = useFiber(current, portal.children || [], expirationTime);
existing['return'] = returnFiber;
return existing;
}
}
function updateFragment(returnFiber, current, fragment, expirationTime, key) {
if (current === null || current.tag !== Fragment) {
// Insert
var created = createFiberFromFragment(fragment, returnFiber.internalContextTag, expirationTime, key);
created['return'] = returnFiber;
return created;
} else {
// Update
var existing = useFiber(current, fragment, expirationTime);
existing['return'] = returnFiber;
return existing;
}
}
function createChild(returnFiber, newChild, expirationTime) {
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys. If the previous node is implicitly keyed
// we can continue to replace it without aborting even if it is not a text
// node.
var created = createFiberFromText('' + newChild, returnFiber.internalContextTag, expirationTime);
created['return'] = returnFiber;
return created;
}
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
{
if (newChild.type === REACT_FRAGMENT_TYPE) {
var _created = createFiberFromFragment(newChild.props.children, returnFiber.internalContextTag, expirationTime, newChild.key);
_created['return'] = returnFiber;
return _created;
} else {
var _created2 = createFiberFromElement(newChild, returnFiber.internalContextTag, expirationTime);
_created2.ref = coerceRef(null, newChild);
_created2['return'] = returnFiber;
return _created2;
}
}
case REACT_CALL_TYPE:
{
var _created3 = createFiberFromCall(newChild, returnFiber.internalContextTag, expirationTime);
_created3['return'] = returnFiber;
return _created3;
}
case REACT_RETURN_TYPE:
{
var _created4 = createFiberFromReturn(newChild, returnFiber.internalContextTag, expirationTime);
_created4.type = newChild.value;
_created4['return'] = returnFiber;
return _created4;
}
case REACT_PORTAL_TYPE:
{
var _created5 = createFiberFromPortal(newChild, returnFiber.internalContextTag, expirationTime);
_created5['return'] = returnFiber;
return _created5;
}
}
if (isArray$1(newChild) || getIteratorFn(newChild)) {
var _created6 = createFiberFromFragment(newChild, returnFiber.internalContextTag, expirationTime, null);
_created6['return'] = returnFiber;
return _created6;
}
throwOnInvalidObjectType(returnFiber, newChild);
}
{
if (typeof newChild === 'function') {
warnOnFunctionType();
}
}
return null;
}
function updateSlot(returnFiber, oldFiber, newChild, expirationTime) {
// Update the fiber if the keys match, otherwise return null.
var key = oldFiber !== null ? oldFiber.key : null;
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys. If the previous node is implicitly keyed
// we can continue to replace it without aborting even if it is not a text
// node.
if (key !== null) {
return null;
}
return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime);
}
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
{
if (newChild.key === key) {
if (newChild.type === REACT_FRAGMENT_TYPE) {
return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key);
}
return updateElement(returnFiber, oldFiber, newChild, expirationTime);
} else {
return null;
}
}
case REACT_CALL_TYPE:
{
if (newChild.key === key) {
return updateCall(returnFiber, oldFiber, newChild, expirationTime);
} else {
return null;
}
}
case REACT_RETURN_TYPE:
{
// Returns don't have keys. If the previous node is implicitly keyed
// we can continue to replace it without aborting even if it is not a
// yield.
if (key === null) {
return updateReturn(returnFiber, oldFiber, newChild, expirationTime);
} else {
return null;
}
}
case REACT_PORTAL_TYPE:
{
if (newChild.key === key) {
return updatePortal(returnFiber, oldFiber, newChild, expirationTime);
} else {
return null;
}
}
}
if (isArray$1(newChild) || getIteratorFn(newChild)) {
if (key !== null) {
return null;
}
return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null);
}
throwOnInvalidObjectType(returnFiber, newChild);
}
{
if (typeof newChild === 'function') {
warnOnFunctionType();
}
}
return null;
}
function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) {
if (typeof newChild === 'string' || typeof newChild === 'number') {
// Text nodes don't have keys, so we neither have to check the old nor
// new node for the key. If both are text nodes, they match.
var matchedFiber = existingChildren.get(newIdx) || null;
return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime);
}
if (typeof newChild === 'object' && newChild !== null) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
{
var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null;
if (newChild.type === REACT_FRAGMENT_TYPE) {
return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key);
}
return updateElement(returnFiber, _matchedFiber, newChild, expirationTime);
}
case REACT_CALL_TYPE:
{
var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null;
return updateCall(returnFiber, _matchedFiber2, newChild, expirationTime);
}
case REACT_RETURN_TYPE:
{
// Returns don't have keys, so we neither have to check the old nor
// new node for the key. If both are returns, they match.
var _matchedFiber3 = existingChildren.get(newIdx) || null;
return updateReturn(returnFiber, _matchedFiber3, newChild, expirationTime);
}
case REACT_PORTAL_TYPE:
{
var _matchedFiber4 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null;
return updatePortal(returnFiber, _matchedFiber4, newChild, expirationTime);
}
}
if (isArray$1(newChild) || getIteratorFn(newChild)) {
var _matchedFiber5 = existingChildren.get(newIdx) || null;
return updateFragment(returnFiber, _matchedFiber5, newChild, expirationTime, null);
}
throwOnInvalidObjectType(returnFiber, newChild);
}
{
if (typeof newChild === 'function') {
warnOnFunctionType();
}
}
return null;
}
/**
* Warns if there is a duplicate or missing key
*/
function warnOnInvalidKey(child, knownKeys) {
{
if (typeof child !== 'object' || child === null) {
return knownKeys;
}
switch (child.$$typeof) {
case REACT_ELEMENT_TYPE:
case REACT_CALL_TYPE:
case REACT_PORTAL_TYPE:
warnForMissingKey(child);
var key = child.key;
if (typeof key !== 'string') {
break;
}
if (knownKeys === null) {
knownKeys = new Set();
knownKeys.add(key);
break;
}
if (!knownKeys.has(key)) {
knownKeys.add(key);
break;
}
warning(false, 'Encountered two children with the same key, `%s`. ' + 'Keys should be unique so that components maintain their identity ' + 'across updates. Non-unique keys may cause children to be ' + 'duplicated and/or omitted — the behavior is unsupported and ' + 'could change in a future version.%s', key, getCurrentFiberStackAddendum$1());
break;
default:
break;
}
}
return knownKeys;
}
function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) {
// This algorithm can't optimize by searching from boths ends since we
// don't have backpointers on fibers. I'm trying to see how far we can get
// with that model. If it ends up not being worth the tradeoffs, we can
// add it later.
// Even with a two ended optimization, we'd want to optimize for the case
// where there are few changes and brute force the comparison instead of
// going for the Map. It'd like to explore hitting that path first in
// forward-only mode and only go for the Map once we notice that we need
// lots of look ahead. This doesn't handle reversal as well as two ended
// search but that's unusual. Besides, for the two ended optimization to
// work on Iterables, we'd need to copy the whole set.
// In this first iteration, we'll just live with hitting the bad case
// (adding everything to a Map) in for every insert/move.
// If you change this code, also update reconcileChildrenIterator() which
// uses the same algorithm.
{
// First, validate keys.
var knownKeys = null;
for (var i = 0; i < newChildren.length; i++) {
var child = newChildren[i];
knownKeys = warnOnInvalidKey(child, knownKeys);
}
}
var resultingFirstChild = null;
var previousNewFiber = null;
var oldFiber = currentFirstChild;
var lastPlacedIndex = 0;
var newIdx = 0;
var nextOldFiber = null;
for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) {
if (oldFiber.index > newIdx) {
nextOldFiber = oldFiber;
oldFiber = null;
} else {
nextOldFiber = oldFiber.sibling;
}
var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime);
if (newFiber === null) {
// TODO: This breaks on empty slots like null children. That's
// unfortunate because it triggers the slow path all the time. We need
// a better way to communicate whether this was a miss or null,
// boolean, undefined, etc.
if (oldFiber === null) {
oldFiber = nextOldFiber;
}
break;
}
if (shouldTrackSideEffects) {
if (oldFiber && newFiber.alternate === null) {
// We matched the slot, but we didn't reuse the existing fiber, so we
// need to delete the existing child.
deleteChild(returnFiber, oldFiber);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = newFiber;
} else {
// TODO: Defer siblings if we're not at the right index for this slot.
// I.e. if we had null values before, then we want to defer this
// for each null value. However, we also don't want to call updateSlot
// with the previous one.
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
if (newIdx === newChildren.length) {
// We've reached the end of the new children. We can delete the rest.
deleteRemainingChildren(returnFiber, oldFiber);
return resultingFirstChild;
}
if (oldFiber === null) {
// If we don't have any more existing children we can choose a fast path
// since the rest will all be insertions.
for (; newIdx < newChildren.length; newIdx++) {
var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime);
if (!_newFiber) {
continue;
}
lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = _newFiber;
} else {
previousNewFiber.sibling = _newFiber;
}
previousNewFiber = _newFiber;
}
return resultingFirstChild;
}
// Add all children to a key map for quick lookups.
var existingChildren = mapRemainingChildren(returnFiber, oldFiber);
// Keep scanning and use the map to restore deleted items as moves.
for (; newIdx < newChildren.length; newIdx++) {
var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime);
if (_newFiber2) {
if (shouldTrackSideEffects) {
if (_newFiber2.alternate !== null) {
// The new fiber is a work in progress, but if there exists a
// current, that means that we reused the fiber. We need to delete
// it from the child list so that we don't add it to the deletion
// list.
existingChildren['delete'](_newFiber2.key === null ? newIdx : _newFiber2.key);
}
}
lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = _newFiber2;
} else {
previousNewFiber.sibling = _newFiber2;
}
previousNewFiber = _newFiber2;
}
}
if (shouldTrackSideEffects) {
// Any existing children that weren't consumed above were deleted. We need
// to add them to the deletion list.
existingChildren.forEach(function (child) {
return deleteChild(returnFiber, child);
});
}
return resultingFirstChild;
}
function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) {
// This is the same implementation as reconcileChildrenArray(),
// but using the iterator instead.
var iteratorFn = getIteratorFn(newChildrenIterable);
!(typeof iteratorFn === 'function') ? invariant(false, 'An object is not an iterable. This error is likely caused by a bug in React. Please file an issue.') : void 0;
{
// Warn about using Maps as children
if (typeof newChildrenIterable.entries === 'function') {
var possibleMap = newChildrenIterable;
if (possibleMap.entries === iteratorFn) {
warning(didWarnAboutMaps, 'Using Maps as children is unsupported and will likely yield ' + 'unexpected results. Convert it to a sequence/iterable of keyed ' + 'ReactElements instead.%s', getCurrentFiberStackAddendum$1());
didWarnAboutMaps = true;
}
}
// First, validate keys.
// We'll get a different iterator later for the main pass.
var _newChildren = iteratorFn.call(newChildrenIterable);
if (_newChildren) {
var knownKeys = null;
var _step = _newChildren.next();
for (; !_step.done; _step = _newChildren.next()) {
var child = _step.value;
knownKeys = warnOnInvalidKey(child, knownKeys);
}
}
}
var newChildren = iteratorFn.call(newChildrenIterable);
!(newChildren != null) ? invariant(false, 'An iterable object provided no iterator.') : void 0;
var resultingFirstChild = null;
var previousNewFiber = null;
var oldFiber = currentFirstChild;
var lastPlacedIndex = 0;
var newIdx = 0;
var nextOldFiber = null;
var step = newChildren.next();
for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) {
if (oldFiber.index > newIdx) {
nextOldFiber = oldFiber;
oldFiber = null;
} else {
nextOldFiber = oldFiber.sibling;
}
var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime);
if (newFiber === null) {
// TODO: This breaks on empty slots like null children. That's
// unfortunate because it triggers the slow path all the time. We need
// a better way to communicate whether this was a miss or null,
// boolean, undefined, etc.
if (!oldFiber) {
oldFiber = nextOldFiber;
}
break;
}
if (shouldTrackSideEffects) {
if (oldFiber && newFiber.alternate === null) {
// We matched the slot, but we didn't reuse the existing fiber, so we
// need to delete the existing child.
deleteChild(returnFiber, oldFiber);
}
}
lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = newFiber;
} else {
// TODO: Defer siblings if we're not at the right index for this slot.
// I.e. if we had null values before, then we want to defer this
// for each null value. However, we also don't want to call updateSlot
// with the previous one.
previousNewFiber.sibling = newFiber;
}
previousNewFiber = newFiber;
oldFiber = nextOldFiber;
}
if (step.done) {
// We've reached the end of the new children. We can delete the rest.
deleteRemainingChildren(returnFiber, oldFiber);
return resultingFirstChild;
}
if (oldFiber === null) {
// If we don't have any more existing children we can choose a fast path
// since the rest will all be insertions.
for (; !step.done; newIdx++, step = newChildren.next()) {
var _newFiber3 = createChild(returnFiber, step.value, expirationTime);
if (_newFiber3 === null) {
continue;
}
lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
// TODO: Move out of the loop. This only happens for the first run.
resultingFirstChild = _newFiber3;
} else {
previousNewFiber.sibling = _newFiber3;
}
previousNewFiber = _newFiber3;
}
return resultingFirstChild;
}
// Add all children to a key map for quick lookups.
var existingChildren = mapRemainingChildren(returnFiber, oldFiber);
// Keep scanning and use the map to restore deleted items as moves.
for (; !step.done; newIdx++, step = newChildren.next()) {
var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime);
if (_newFiber4 !== null) {
if (shouldTrackSideEffects) {
if (_newFiber4.alternate !== null) {
// The new fiber is a work in progress, but if there exists a
// current, that means that we reused the fiber. We need to delete
// it from the child list so that we don't add it to the deletion
// list.
existingChildren['delete'](_newFiber4.key === null ? newIdx : _newFiber4.key);
}
}
lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx);
if (previousNewFiber === null) {
resultingFirstChild = _newFiber4;
} else {
previousNewFiber.sibling = _newFiber4;
}
previousNewFiber = _newFiber4;
}
}
if (shouldTrackSideEffects) {
// Any existing children that weren't consumed above were deleted. We need
// to add them to the deletion list.
existingChildren.forEach(function (child) {
return deleteChild(returnFiber, child);
});
}
return resultingFirstChild;
}
function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) {
// There's no need to check for keys on text nodes since we don't have a
// way to define them.
if (currentFirstChild !== null && currentFirstChild.tag === HostText) {
// We already have an existing node so let's just update it and delete
// the rest.
deleteRemainingChildren(returnFiber, currentFirstChild.sibling);
var existing = useFiber(currentFirstChild, textContent, expirationTime);
existing['return'] = returnFiber;
return existing;
}
// The existing first child is not a text node so we need to create one
// and delete the existing ones.
deleteRemainingChildren(returnFiber, currentFirstChild);
var created = createFiberFromText(textContent, returnFiber.internalContextTag, expirationTime);
created['return'] = returnFiber;
return created;
}
function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) {
var key = element.key;
var child = currentFirstChild;
while (child !== null) {
// TODO: If key === null and child.key === null, then this only applies to
// the first item in the list.
if (child.key === key) {
if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.type === element.type) {
deleteRemainingChildren(returnFiber, child.sibling);
var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime);
existing.ref = coerceRef(child, element);
existing['return'] = returnFiber;
{
existing._debugSource = element._source;
existing._debugOwner = element._owner;
}
return existing;
} else {
deleteRemainingChildren(returnFiber, child);
break;
}
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
if (element.type === REACT_FRAGMENT_TYPE) {
var created = createFiberFromFragment(element.props.children, returnFiber.internalContextTag, expirationTime, element.key);
created['return'] = returnFiber;
return created;
} else {
var _created7 = createFiberFromElement(element, returnFiber.internalContextTag, expirationTime);
_created7.ref = coerceRef(currentFirstChild, element);
_created7['return'] = returnFiber;
return _created7;
}
}
function reconcileSingleCall(returnFiber, currentFirstChild, call, expirationTime) {
var key = call.key;
var child = currentFirstChild;
while (child !== null) {
// TODO: If key === null and child.key === null, then this only applies to
// the first item in the list.
if (child.key === key) {
if (child.tag === CallComponent) {
deleteRemainingChildren(returnFiber, child.sibling);
var existing = useFiber(child, call, expirationTime);
existing['return'] = returnFiber;
return existing;
} else {
deleteRemainingChildren(returnFiber, child);
break;
}
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
var created = createFiberFromCall(call, returnFiber.internalContextTag, expirationTime);
created['return'] = returnFiber;
return created;
}
function reconcileSingleReturn(returnFiber, currentFirstChild, returnNode, expirationTime) {
// There's no need to check for keys on yields since they're stateless.
var child = currentFirstChild;
if (child !== null) {
if (child.tag === ReturnComponent) {
deleteRemainingChildren(returnFiber, child.sibling);
var existing = useFiber(child, null, expirationTime);
existing.type = returnNode.value;
existing['return'] = returnFiber;
return existing;
} else {
deleteRemainingChildren(returnFiber, child);
}
}
var created = createFiberFromReturn(returnNode, returnFiber.internalContextTag, expirationTime);
created.type = returnNode.value;
created['return'] = returnFiber;
return created;
}
function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) {
var key = portal.key;
var child = currentFirstChild;
while (child !== null) {
// TODO: If key === null and child.key === null, then this only applies to
// the first item in the list.
if (child.key === key) {
if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) {
deleteRemainingChildren(returnFiber, child.sibling);
var existing = useFiber(child, portal.children || [], expirationTime);
existing['return'] = returnFiber;
return existing;
} else {
deleteRemainingChildren(returnFiber, child);
break;
}
} else {
deleteChild(returnFiber, child);
}
child = child.sibling;
}
var created = createFiberFromPortal(portal, returnFiber.internalContextTag, expirationTime);
created['return'] = returnFiber;
return created;
}
// This API will tag the children with the side-effect of the reconciliation
// itself. They will be added to the side-effect list as we pass through the
// children and the parent.
function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) {
// This function is not recursive.
// If the top level item is an array, we treat it as a set of children,
// not as a fragment. Nested arrays on the other hand will be treated as
// fragment nodes. Recursion happens at the normal flow.
// Handle top level unkeyed fragments as if they were arrays.
// This leads to an ambiguity between <>{[...]}> and <>...>.
// We treat the ambiguous cases above the same.
if (typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null) {
newChild = newChild.props.children;
}
// Handle object types
var isObject = typeof newChild === 'object' && newChild !== null;
if (isObject) {
switch (newChild.$$typeof) {
case REACT_ELEMENT_TYPE:
return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime));
case REACT_CALL_TYPE:
return placeSingleChild(reconcileSingleCall(returnFiber, currentFirstChild, newChild, expirationTime));
case REACT_RETURN_TYPE:
return placeSingleChild(reconcileSingleReturn(returnFiber, currentFirstChild, newChild, expirationTime));
case REACT_PORTAL_TYPE:
return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime));
}
}
if (typeof newChild === 'string' || typeof newChild === 'number') {
return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime));
}
if (isArray$1(newChild)) {
return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime);
}
if (getIteratorFn(newChild)) {
return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime);
}
if (isObject) {
throwOnInvalidObjectType(returnFiber, newChild);
}
{
if (typeof newChild === 'function') {
warnOnFunctionType();
}
}
if (typeof newChild === 'undefined') {
// If the new child is undefined, and the return fiber is a composite
// component, throw an error. If Fiber return types are disabled,
// we already threw above.
switch (returnFiber.tag) {
case ClassComponent:
{
{
var instance = returnFiber.stateNode;
if (instance.render._isMockFunction) {
// We allow auto-mocks to proceed as if they're returning null.
break;
}
}
}
// Intentionally fall through to the next case, which handles both
// functions and classes
// eslint-disable-next-lined no-fallthrough
case FunctionalComponent:
{
var Component = returnFiber.type;
invariant(false, '%s(...): Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.', Component.displayName || Component.name || 'Component');
}
}
}
// Remaining cases are all treated as empty.
return deleteRemainingChildren(returnFiber, currentFirstChild);
}
return reconcileChildFibers;
}
var reconcileChildFibers = ChildReconciler(true);
var mountChildFibers = ChildReconciler(false);
function cloneChildFibers(current, workInProgress) {
!(current === null || workInProgress.child === current.child) ? invariant(false, 'Resuming work not yet implemented.') : void 0;
if (workInProgress.child === null) {
return;
}
var currentChild = workInProgress.child;
var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime);
workInProgress.child = newChild;
newChild['return'] = workInProgress;
while (currentChild.sibling !== null) {
currentChild = currentChild.sibling;
newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime);
newChild['return'] = workInProgress;
}
newChild.sibling = null;
}
{
var warnedAboutStatelessRefs = {};
}
var ReactFiberBeginWork = function (config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber) {
var shouldSetTextContent = config.shouldSetTextContent,
useSyncScheduling = config.useSyncScheduling,
shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree;
var pushHostContext = hostContext.pushHostContext,
pushHostContainer = hostContext.pushHostContainer;
var enterHydrationState = hydrationContext.enterHydrationState,
resetHydrationState = hydrationContext.resetHydrationState,
tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance;
var _ReactFiberClassCompo = ReactFiberClassComponent(scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState),
adoptClassInstance = _ReactFiberClassCompo.adoptClassInstance,
constructClassInstance = _ReactFiberClassCompo.constructClassInstance,
mountClassInstance = _ReactFiberClassCompo.mountClassInstance,
updateClassInstance = _ReactFiberClassCompo.updateClassInstance;
// TODO: Remove this and use reconcileChildrenAtExpirationTime directly.
function reconcileChildren(current, workInProgress, nextChildren) {
reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, workInProgress.expirationTime);
}
function reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, renderExpirationTime) {
if (current === null) {
// If this is a fresh new component that hasn't been rendered yet, we
// won't update its child set by applying minimal side-effects. Instead,
// we will add them all to the child before it gets rendered. That means
// we can optimize this reconciliation pass by not tracking side-effects.
workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
} else {
// If the current child is the same as the work in progress, it means that
// we haven't yet started any work on these children. Therefore, we use
// the clone algorithm to create a copy of all the current children.
// If we had any progressed work already, that is invalid at this point so
// let's throw it out.
workInProgress.child = reconcileChildFibers(workInProgress, current.child, nextChildren, renderExpirationTime);
}
}
function updateFragment(current, workInProgress) {
var nextChildren = workInProgress.pendingProps;
if (hasContextChanged()) {
// Normally we can bail out on props equality but if context has changed
// we don't do the bailout and we have to reuse existing props instead.
if (nextChildren === null) {
nextChildren = workInProgress.memoizedProps;
}
} else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
reconcileChildren(current, workInProgress, nextChildren);
memoizeProps(workInProgress, nextChildren);
return workInProgress.child;
}
function markRef(current, workInProgress) {
var ref = workInProgress.ref;
if (ref !== null && (!current || current.ref !== ref)) {
// Schedule a Ref effect
workInProgress.effectTag |= Ref;
}
}
function updateFunctionalComponent(current, workInProgress) {
var fn = workInProgress.type;
var nextProps = workInProgress.pendingProps;
var memoizedProps = workInProgress.memoizedProps;
if (hasContextChanged()) {
// Normally we can bail out on props equality but if context has changed
// we don't do the bailout and we have to reuse existing props instead.
if (nextProps === null) {
nextProps = memoizedProps;
}
} else {
if (nextProps === null || memoizedProps === nextProps) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
// TODO: consider bringing fn.shouldComponentUpdate() back.
// It used to be here.
}
var unmaskedContext = getUnmaskedContext(workInProgress);
var context = getMaskedContext(workInProgress, unmaskedContext);
var nextChildren;
{
ReactCurrentOwner.current = workInProgress;
ReactDebugCurrentFiber.setCurrentPhase('render');
nextChildren = fn(nextProps, context);
ReactDebugCurrentFiber.setCurrentPhase(null);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
reconcileChildren(current, workInProgress, nextChildren);
memoizeProps(workInProgress, nextProps);
return workInProgress.child;
}
function updateClassComponent(current, workInProgress, renderExpirationTime) {
// Push context providers early to prevent context stack mismatches.
// During mounting we don't know the child context yet as the instance doesn't exist.
// We will invalidate the child context in finishClassComponent() right after rendering.
var hasContext = pushContextProvider(workInProgress);
var shouldUpdate = void 0;
if (current === null) {
if (!workInProgress.stateNode) {
// In the initial pass we might need to construct the instance.
constructClassInstance(workInProgress, workInProgress.pendingProps);
mountClassInstance(workInProgress, renderExpirationTime);
shouldUpdate = true;
} else {
invariant(false, 'Resuming work not yet implemented.');
// In a resume, we'll already have an instance we can reuse.
// shouldUpdate = resumeMountClassInstance(workInProgress, renderExpirationTime);
}
} else {
shouldUpdate = updateClassInstance(current, workInProgress, renderExpirationTime);
}
return finishClassComponent(current, workInProgress, shouldUpdate, hasContext);
}
function finishClassComponent(current, workInProgress, shouldUpdate, hasContext) {
// Refs should update even if shouldComponentUpdate returns false
markRef(current, workInProgress);
if (!shouldUpdate) {
// Context providers should defer to sCU for rendering
if (hasContext) {
invalidateContextProvider(workInProgress, false);
}
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
var instance = workInProgress.stateNode;
// Rerender
ReactCurrentOwner.current = workInProgress;
var nextChildren = void 0;
{
ReactDebugCurrentFiber.setCurrentPhase('render');
nextChildren = instance.render();
if (debugRenderPhaseSideEffects) {
instance.render();
}
ReactDebugCurrentFiber.setCurrentPhase(null);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
reconcileChildren(current, workInProgress, nextChildren);
// Memoize props and state using the values we just used to render.
// TODO: Restructure so we never read values from the instance.
memoizeState(workInProgress, instance.state);
memoizeProps(workInProgress, instance.props);
// The context might have changed so we need to recalculate it.
if (hasContext) {
invalidateContextProvider(workInProgress, true);
}
return workInProgress.child;
}
function pushHostRootContext(workInProgress) {
var root = workInProgress.stateNode;
if (root.pendingContext) {
pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context);
} else if (root.context) {
// Should always be set
pushTopLevelContextObject(workInProgress, root.context, false);
}
pushHostContainer(workInProgress, root.containerInfo);
}
function updateHostRoot(current, workInProgress, renderExpirationTime) {
pushHostRootContext(workInProgress);
var updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
var prevState = workInProgress.memoizedState;
var state = processUpdateQueue(current, workInProgress, updateQueue, null, null, renderExpirationTime);
if (prevState === state) {
// If the state is the same as before, that's a bailout because we had
// no work that expires at this time.
resetHydrationState();
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
var element = state.element;
var root = workInProgress.stateNode;
if ((current === null || current.child === null) && root.hydrate && enterHydrationState(workInProgress)) {
// If we don't have any current children this might be the first pass.
// We always try to hydrate. If this isn't a hydration pass there won't
// be any children to hydrate which is effectively the same thing as
// not hydrating.
// This is a bit of a hack. We track the host root as a placement to
// know that we're currently in a mounting state. That way isMounted
// works as expected. We must reset this before committing.
// TODO: Delete this when we delete isMounted and findDOMNode.
workInProgress.effectTag |= Placement;
// Ensure that children mount into this root without tracking
// side-effects. This ensures that we don't store Placement effects on
// nodes that will be hydrated.
workInProgress.child = mountChildFibers(workInProgress, null, element, renderExpirationTime);
} else {
// Otherwise reset hydration state in case we aborted and resumed another
// root.
resetHydrationState();
reconcileChildren(current, workInProgress, element);
}
memoizeState(workInProgress, state);
return workInProgress.child;
}
resetHydrationState();
// If there is no update queue, that's a bailout because the root has no props.
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
function updateHostComponent(current, workInProgress, renderExpirationTime) {
pushHostContext(workInProgress);
if (current === null) {
tryToClaimNextHydratableInstance(workInProgress);
}
var type = workInProgress.type;
var memoizedProps = workInProgress.memoizedProps;
var nextProps = workInProgress.pendingProps;
if (nextProps === null) {
nextProps = memoizedProps;
!(nextProps !== null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0;
}
var prevProps = current !== null ? current.memoizedProps : null;
if (hasContextChanged()) {
// Normally we can bail out on props equality but if context has changed
// we don't do the bailout and we have to reuse existing props instead.
} else if (nextProps === null || memoizedProps === nextProps) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
var nextChildren = nextProps.children;
var isDirectTextChild = shouldSetTextContent(type, nextProps);
if (isDirectTextChild) {
// We special case a direct text child of a host node. This is a common
// case. We won't handle it as a reified child. We will instead handle
// this in the host environment that also have access to this prop. That
// avoids allocating another HostText fiber and traversing it.
nextChildren = null;
} else if (prevProps && shouldSetTextContent(type, prevProps)) {
// If we're switching from a direct text child to a normal child, or to
// empty, we need to schedule the text content to be reset.
workInProgress.effectTag |= ContentReset;
}
markRef(current, workInProgress);
// Check the host config to see if the children are offscreen/hidden.
if (renderExpirationTime !== Never && !useSyncScheduling && shouldDeprioritizeSubtree(type, nextProps)) {
// Down-prioritize the children.
workInProgress.expirationTime = Never;
// Bailout and come back to this fiber later.
return null;
}
reconcileChildren(current, workInProgress, nextChildren);
memoizeProps(workInProgress, nextProps);
return workInProgress.child;
}
function updateHostText(current, workInProgress) {
if (current === null) {
tryToClaimNextHydratableInstance(workInProgress);
}
var nextProps = workInProgress.pendingProps;
if (nextProps === null) {
nextProps = workInProgress.memoizedProps;
}
memoizeProps(workInProgress, nextProps);
// Nothing to do here. This is terminal. We'll do the completion step
// immediately after.
return null;
}
function mountIndeterminateComponent(current, workInProgress, renderExpirationTime) {
!(current === null) ? invariant(false, 'An indeterminate component should never have mounted. This error is likely caused by a bug in React. Please file an issue.') : void 0;
var fn = workInProgress.type;
var props = workInProgress.pendingProps;
var unmaskedContext = getUnmaskedContext(workInProgress);
var context = getMaskedContext(workInProgress, unmaskedContext);
var value;
{
if (fn.prototype && typeof fn.prototype.render === 'function') {
var componentName = getComponentName(workInProgress);
warning(false, "The <%s /> component appears to have a render method, but doesn't extend React.Component. " + 'This is likely to cause errors. Change %s to extend React.Component instead.', componentName, componentName);
}
ReactCurrentOwner.current = workInProgress;
value = fn(props, context);
}
// React DevTools reads this flag.
workInProgress.effectTag |= PerformedWork;
if (typeof value === 'object' && value !== null && typeof value.render === 'function') {
// Proceed under the assumption that this is a class instance
workInProgress.tag = ClassComponent;
// Push context providers early to prevent context stack mismatches.
// During mounting we don't know the child context yet as the instance doesn't exist.
// We will invalidate the child context in finishClassComponent() right after rendering.
var hasContext = pushContextProvider(workInProgress);
adoptClassInstance(workInProgress, value);
mountClassInstance(workInProgress, renderExpirationTime);
return finishClassComponent(current, workInProgress, true, hasContext);
} else {
// Proceed under the assumption that this is a functional component
workInProgress.tag = FunctionalComponent;
{
var Component = workInProgress.type;
if (Component) {
warning(!Component.childContextTypes, '%s(...): childContextTypes cannot be defined on a functional component.', Component.displayName || Component.name || 'Component');
}
if (workInProgress.ref !== null) {
var info = '';
var ownerName = ReactDebugCurrentFiber.getCurrentFiberOwnerName();
if (ownerName) {
info += '\n\nCheck the render method of `' + ownerName + '`.';
}
var warningKey = ownerName || workInProgress._debugID || '';
var debugSource = workInProgress._debugSource;
if (debugSource) {
warningKey = debugSource.fileName + ':' + debugSource.lineNumber;
}
if (!warnedAboutStatelessRefs[warningKey]) {
warnedAboutStatelessRefs[warningKey] = true;
warning(false, 'Stateless function components cannot be given refs. ' + 'Attempts to access this ref will fail.%s%s', info, ReactDebugCurrentFiber.getCurrentFiberStackAddendum());
}
}
}
reconcileChildren(current, workInProgress, value);
memoizeProps(workInProgress, props);
return workInProgress.child;
}
}
function updateCallComponent(current, workInProgress, renderExpirationTime) {
var nextCall = workInProgress.pendingProps;
if (hasContextChanged()) {
// Normally we can bail out on props equality but if context has changed
// we don't do the bailout and we have to reuse existing props instead.
if (nextCall === null) {
nextCall = current && current.memoizedProps;
!(nextCall !== null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0;
}
} else if (nextCall === null || workInProgress.memoizedProps === nextCall) {
nextCall = workInProgress.memoizedProps;
// TODO: When bailing out, we might need to return the stateNode instead
// of the child. To check it for work.
// return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
var nextChildren = nextCall.children;
// The following is a fork of reconcileChildrenAtExpirationTime but using
// stateNode to store the child.
if (current === null) {
workInProgress.stateNode = mountChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime);
} else {
workInProgress.stateNode = reconcileChildFibers(workInProgress, workInProgress.stateNode, nextChildren, renderExpirationTime);
}
memoizeProps(workInProgress, nextCall);
// This doesn't take arbitrary time so we could synchronously just begin
// eagerly do the work of workInProgress.child as an optimization.
return workInProgress.stateNode;
}
function updatePortalComponent(current, workInProgress, renderExpirationTime) {
pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);
var nextChildren = workInProgress.pendingProps;
if (hasContextChanged()) {
// Normally we can bail out on props equality but if context has changed
// we don't do the bailout and we have to reuse existing props instead.
if (nextChildren === null) {
nextChildren = current && current.memoizedProps;
!(nextChildren != null) ? invariant(false, 'We should always have pending or current props. This error is likely caused by a bug in React. Please file an issue.') : void 0;
}
} else if (nextChildren === null || workInProgress.memoizedProps === nextChildren) {
return bailoutOnAlreadyFinishedWork(current, workInProgress);
}
if (current === null) {
// 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 = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime);
memoizeProps(workInProgress, nextChildren);
} else {
reconcileChildren(current, workInProgress, nextChildren);
memoizeProps(workInProgress, nextChildren);
}
return workInProgress.child;
}
/*
function reuseChildrenEffects(returnFiber : Fiber, firstChild : Fiber) {
let child = firstChild;
do {
// Ensure that the first and last effect of the parent corresponds
// to the children's first and last effect.
if (!returnFiber.firstEffect) {
returnFiber.firstEffect = child.firstEffect;
}
if (child.lastEffect) {
if (returnFiber.lastEffect) {
returnFiber.lastEffect.nextEffect = child.firstEffect;
}
returnFiber.lastEffect = child.lastEffect;
}
} while (child = child.sibling);
}
*/
function bailoutOnAlreadyFinishedWork(current, workInProgress) {
cancelWorkTimer(workInProgress);
// TODO: We should ideally be able to bail out early if the children have no
// more work to do. However, since we don't have a separation of this
// Fiber's priority and its children yet - we don't know without doing lots
// of the same work we do anyway. Once we have that separation we can just
// bail out here if the children has no more work at this priority level.
// if (workInProgress.priorityOfChildren <= priorityLevel) {
// // If there are side-effects in these children that have not yet been
// // committed we need to ensure that they get properly transferred up.
// if (current && current.child !== workInProgress.child) {
// reuseChildrenEffects(workInProgress, child);
// }
// return null;
// }
cloneChildFibers(current, workInProgress);
return workInProgress.child;
}
function bailoutOnLowPriority(current, workInProgress) {
cancelWorkTimer(workInProgress);
// TODO: Handle HostComponent tags here as well and call pushHostContext()?
// See PR 8590 discussion for context
switch (workInProgress.tag) {
case HostRoot:
pushHostRootContext(workInProgress);
break;
case ClassComponent:
pushContextProvider(workInProgress);
break;
case HostPortal:
pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo);
break;
}
// TODO: What if this is currently in progress?
// How can that happen? How is this not being cloned?
return null;
}
// TODO: Delete memoizeProps/State and move to reconcile/bailout instead
function memoizeProps(workInProgress, nextProps) {
workInProgress.memoizedProps = nextProps;
}
function memoizeState(workInProgress, nextState) {
workInProgress.memoizedState = nextState;
// Don't reset the updateQueue, in case there are pending updates. Resetting
// is handled by processUpdateQueue.
}
function beginWork(current, workInProgress, renderExpirationTime) {
if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) {
return bailoutOnLowPriority(current, workInProgress);
}
switch (workInProgress.tag) {
case IndeterminateComponent:
return mountIndeterminateComponent(current, workInProgress, renderExpirationTime);
case FunctionalComponent:
return updateFunctionalComponent(current, workInProgress);
case ClassComponent:
return updateClassComponent(current, workInProgress, renderExpirationTime);
case HostRoot:
return updateHostRoot(current, workInProgress, renderExpirationTime);
case HostComponent:
return updateHostComponent(current, workInProgress, renderExpirationTime);
case HostText:
return updateHostText(current, workInProgress);
case CallHandlerPhase:
// This is a restart. Reset the tag to the initial phase.
workInProgress.tag = CallComponent;
// Intentionally fall through since this is now the same.
case CallComponent:
return updateCallComponent(current, workInProgress, renderExpirationTime);
case ReturnComponent:
// A return component is just a placeholder, we can just run through the
// next one immediately.
return null;
case HostPortal:
return updatePortalComponent(current, workInProgress, renderExpirationTime);
case Fragment:
return updateFragment(current, workInProgress);
default:
invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
}
}
function beginFailedWork(current, workInProgress, renderExpirationTime) {
// Push context providers here to avoid a push/pop context mismatch.
switch (workInProgress.tag) {
case ClassComponent:
pushContextProvider(workInProgress);
break;
case HostRoot:
pushHostRootContext(workInProgress);
break;
default:
invariant(false, 'Invalid type of work. This error is likely caused by a bug in React. Please file an issue.');
}
// Add an error effect so we can handle the error during the commit phase
workInProgress.effectTag |= Err;
// This is a weird case where we do "resume" work — work that failed on
// our first attempt. Because we no longer have a notion of "progressed
// deletions," reset the child to the current child to make sure we delete
// it again. TODO: Find a better way to handle this, perhaps during a more
// general overhaul of error handling.
if (current === null) {
workInProgress.child = null;
} else if (workInProgress.child !== current.child) {
workInProgress.child = current.child;
}
if (workInProgress.expirationTime === NoWork || workInProgress.expirationTime > renderExpirationTime) {
return bailoutOnLowPriority(current, workInProgress);
}
// If we don't bail out, we're going be recomputing our children so we need
// to drop our effect list.
workInProgress.firstEffect = null;
workInProgress.lastEffect = null;
// Unmount the current children as if the component rendered null
var nextChildren = null;
reconcileChildrenAtExpirationTime(current, workInProgress, nextChildren, renderExpirationTime);
if (workInProgress.tag === ClassComponent) {
var instance = workInProgress.stateNode;
workInProgress.memoizedProps = instance.props;
workInProgress.memoizedState = instance.state;
}
return workInProgress.child;
}
return {
beginWork: beginWork,
beginFailedWork: beginFailedWork
};
};
var ReactFiberCompleteWork = function (config, hostContext, hydrationContext) {
var createInstance = config.createInstance,
createTextInstance = config.createTextInstance,
appendInitialChild = config.appendInitialChild,
finalizeInitialChildren = config.finalizeInitialChildren,
prepareUpdate = config.prepareUpdate,
mutation = config.mutation,
persistence = config.persistence;
var getRootHostContainer = hostContext.getRootHostContainer,
popHostContext = hostContext.popHostContext,
getHostContext = hostContext.getHostContext,
popHostContainer = hostContext.popHostContainer;
var prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance,
prepareToHydrateHostTextInstance = hydrationContext.prepareToHydrateHostTextInstance,
popHydrationState = hydrationContext.popHydrationState;
function markUpdate(workInProgress) {
// Tag the fiber with an update effect. This turns a Placement into
// an UpdateAndPlacement.
workInProgress.effectTag |= Update;
}
function markRef(workInProgress) {
workInProgress.effectTag |= Ref;
}
function appendAllReturns(returns, workInProgress) {
var node = workInProgress.stateNode;
if (node) {
node['return'] = workInProgress;
}
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText || node.tag === HostPortal) {
invariant(false, 'A call cannot have host component children.');
} else if (node.tag === ReturnComponent) {
returns.push(node.type);
} else if (node.child !== null) {
node.child['return'] = node;
node = node.child;
continue;
}
while (node.sibling === null) {
if (node['return'] === null || node['return'] === workInProgress) {
return;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
}
function moveCallToHandlerPhase(current, workInProgress, renderExpirationTime) {
var call = workInProgress.memoizedProps;
!call ? invariant(false, 'Should be resolved by now. This error is likely caused by a bug in React. Please file an issue.') : void 0;
// First step of the call has completed. Now we need to do the second.
// TODO: It would be nice to have a multi stage call represented by a
// single component, or at least tail call optimize nested ones. Currently
// that requires additional fields that we don't want to add to the fiber.
// So this requires nested handlers.
// Note: This doesn't mutate the alternate node. I don't think it needs to
// since this stage is reset for every pass.
workInProgress.tag = CallHandlerPhase;
// Build up the returns.
// TODO: Compare this to a generator or opaque helpers like Children.
var returns = [];
appendAllReturns(returns, workInProgress);
var fn = call.handler;
var props = call.props;
var nextChildren = fn(props, returns);
var currentFirstChild = current !== null ? current.child : null;
workInProgress.child = reconcileChildFibers(workInProgress, currentFirstChild, nextChildren, renderExpirationTime);
return workInProgress.child;
}
function appendAllChildren(parent, workInProgress) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
var node = workInProgress.child;
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText) {
appendInitialChild(parent, node.stateNode);
} 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.child !== null) {
node.child['return'] = node;
node = node.child;
continue;
}
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node['return'] === null || node['return'] === workInProgress) {
return;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
}
var updateHostContainer = void 0;
var updateHostComponent = void 0;
var updateHostText = void 0;
if (mutation) {
if (enableMutatingReconciler) {
// Mutation mode
updateHostContainer = function (workInProgress) {
// Noop
};
updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) {
// TODO: Type this specific to this type of component.
workInProgress.updateQueue = updatePayload;
// If the update payload indicates that there is a change or if there
// is a new ref we mark this as an update. All the work is done in commitWork.
if (updatePayload) {
markUpdate(workInProgress);
}
};
updateHostText = function (current, workInProgress, oldText, newText) {
// If the text differs, mark it as an update. All the work in done in commitWork.
if (oldText !== newText) {
markUpdate(workInProgress);
}
};
} else {
invariant(false, 'Mutating reconciler is disabled.');
}
} else if (persistence) {
if (enablePersistentReconciler) {
// Persistent host tree mode
var cloneInstance = persistence.cloneInstance,
createContainerChildSet = persistence.createContainerChildSet,
appendChildToContainerChildSet = persistence.appendChildToContainerChildSet,
finalizeContainerChildren = persistence.finalizeContainerChildren;
// An unfortunate fork of appendAllChildren because we have two different parent types.
var appendAllChildrenToContainer = function (containerChildSet, workInProgress) {
// We only have the top Fiber that was created but we need recurse down its
// children to find all the terminal nodes.
var node = workInProgress.child;
while (node !== null) {
if (node.tag === HostComponent || node.tag === HostText) {
appendChildToContainerChildSet(containerChildSet, node.stateNode);
} 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.child !== null) {
node.child['return'] = node;
node = node.child;
continue;
}
if (node === workInProgress) {
return;
}
while (node.sibling === null) {
if (node['return'] === null || node['return'] === workInProgress) {
return;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
};
updateHostContainer = function (workInProgress) {
var portalOrRoot = workInProgress.stateNode;
var childrenUnchanged = workInProgress.firstEffect === null;
if (childrenUnchanged) {
// No changes, just reuse the existing instance.
} else {
var container = portalOrRoot.containerInfo;
var newChildSet = createContainerChildSet(container);
if (finalizeContainerChildren(container, newChildSet)) {
markUpdate(workInProgress);
}
portalOrRoot.pendingChildren = newChildSet;
// If children might have changed, we have to add them all to the set.
appendAllChildrenToContainer(newChildSet, workInProgress);
// Schedule an update on the container to swap out the container.
markUpdate(workInProgress);
}
};
updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) {
// If there are no effects associated with this node, then none of our children had any updates.
// This guarantees that we can reuse all of them.
var childrenUnchanged = workInProgress.firstEffect === null;
var currentInstance = current.stateNode;
if (childrenUnchanged && updatePayload === null) {
// No changes, just reuse the existing instance.
// Note that this might release a previous clone.
workInProgress.stateNode = currentInstance;
} else {
var recyclableInstance = workInProgress.stateNode;
var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance);
if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance)) {
markUpdate(workInProgress);
}
workInProgress.stateNode = newInstance;
if (childrenUnchanged) {
// If there are no other effects in this tree, we need to flag this node as having one.
// Even though we're not going to use it for anything.
// Otherwise parents won't know that there are new children to propagate upwards.
markUpdate(workInProgress);
} else {
// If children might have changed, we have to add them all to the set.
appendAllChildren(newInstance, workInProgress);
}
}
};
updateHostText = function (current, workInProgress, oldText, newText) {
if (oldText !== newText) {
// If the text content differs, we'll create a new text instance for it.
var rootContainerInstance = getRootHostContainer();
var currentHostContext = getHostContext();
workInProgress.stateNode = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress);
// We'll have to mark it as having an effect, even though we won't use the effect for anything.
// This lets the parents know that at least one of their children has changed.
markUpdate(workInProgress);
}
};
} else {
invariant(false, 'Persistent reconciler is disabled.');
}
} else {
if (enableNoopReconciler) {
// No host operations
updateHostContainer = function (workInProgress) {
// Noop
};
updateHostComponent = function (current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance) {
// Noop
};
updateHostText = function (current, workInProgress, oldText, newText) {
// Noop
};
} else {
invariant(false, 'Noop reconciler is disabled.');
}
}
function completeWork(current, workInProgress, renderExpirationTime) {
// Get the latest props.
var newProps = workInProgress.pendingProps;
if (newProps === null) {
newProps = workInProgress.memoizedProps;
} else if (workInProgress.expirationTime !== Never || renderExpirationTime === Never) {
// Reset the pending props, unless this was a down-prioritization.
workInProgress.pendingProps = null;
}
switch (workInProgress.tag) {
case FunctionalComponent:
return null;
case ClassComponent:
{
// We are leaving this subtree, so pop context if any.
popContextProvider(workInProgress);
return null;
}
case HostRoot:
{
popHostContainer(workInProgress);
popTopLevelContextObject(workInProgress);
var fiberRoot = workInProgress.stateNode;
if (fiberRoot.pendingContext) {
fiberRoot.context = fiberRoot.pendingContext;
fiberRoot.pendingContext = null;
}
if (current === null || current.child === null) {
// If we hydrated, pop so that we can delete any remaining children
// that weren't hydrated.
popHydrationState(workInProgress);
// This resets the hacky state to fix isMounted before committing.
// TODO: Delete this when we delete isMounted and findDOMNode.
workInProgress.effectTag &= ~Placement;
}
updateHostContainer(workInProgress);
return null;
}
case HostComponent:
{
popHostContext(workInProgress);
var rootContainerInstance = getRootHostContainer();
var type = workInProgress.type;
if (current !== null && workInProgress.stateNode != null) {
// If we have an alternate, that means this is an update and we need to
// schedule a side-effect to do the updates.
var oldProps = current.memoizedProps;
// If we get updated because one of our children updated, we don't
// have newProps so we'll have to reuse them.
// TODO: Split the update API as separate for the props vs. children.
// Even better would be if children weren't special cased at all tho.
var instance = workInProgress.stateNode;
var currentHostContext = getHostContext();
var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext);
updateHostComponent(current, workInProgress, updatePayload, type, oldProps, newProps, rootContainerInstance);
if (current.ref !== workInProgress.ref) {
markRef(workInProgress);
}
} else {
if (!newProps) {
!(workInProgress.stateNode !== null) ? invariant(false, 'We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.') : void 0;
// This can happen when we abort work.
return null;
}
var _currentHostContext = getHostContext();
// 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.
var wasHydrated = popHydrationState(workInProgress);
if (wasHydrated) {
// TODO: Move this and createInstance step into the beginPhase
// to consolidate.
if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, _currentHostContext)) {
// If changes to the hydrated node needs to be applied at the
// commit-phase we mark this as such.
markUpdate(workInProgress);
}
} else {
var _instance = createInstance(type, newProps, rootContainerInstance, _currentHostContext, workInProgress);
appendAllChildren(_instance, workInProgress);
// Certain renderers require commit-time effects for initial mount.
// (eg DOM renderer supports auto-focus for certain elements).
// Make sure such renderers get scheduled for later work.
if (finalizeInitialChildren(_instance, type, newProps, rootContainerInstance)) {
markUpdate(workInProgress);
}
workInProgress.stateNode = _instance;
}
if (workInProgress.ref !== null) {
// If there is a ref on a host node we need to schedule a callback
markRef(workInProgress);
}
}
return null;
}
case HostText:
{
var newText = newProps;
if (current && workInProgress.stateNode != null) {
var oldText = current.memoizedProps;
// If we have an alternate, that means this is an update and we need
// to schedule a side-effect to do the updates.
updateHostText(current, workInProgress, oldText, newText);
} else {
if (typeof newText !== 'string') {
!(workInProgress.stateNode !== null) ? invariant(false, 'We must have new props for new mounts. This error is likely caused by a bug in React. Please file an issue.') : void 0;
// This can happen when we abort work.
return null;
}
var _rootContainerInstance = getRootHostContainer();
var _currentHostContext2 = getHostContext();
var _wasHydrated = popHydrationState(workInProgress);
if (_wasHydrated) {
if (prepareToHydrateHostTextInstance(workInProgress)) {
markUpdate(workInProgress);
}
} else {
workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext2, workInProgress);
}
}
return null;
}
case CallComponent:
return moveCallToHandlerPhase(current, workInProgress, renderExpirationTime);
case CallHandlerPhase:
// Reset the tag to now be a first phase call.
workInProgress.tag = CallComponent;
return null;
case ReturnComponent:
// Does nothing.
return null;
case Fragment:
return null;
case HostPortal:
popHostContainer(workInProgress);
updateHostContainer(workInProgress);
return null;
// Error cases
case IndeterminateComponent:
invariant(false, 'An indeterminate component should have become determinate before completing. This error is likely caused by a bug in React. Please file an issue.');
// eslint-disable-next-line no-fallthrough
default:
invariant(false, 'Unknown unit of work tag. This error is likely caused by a bug in React. Please file an issue.');
}
}
return {
completeWork: completeWork
};
};
var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback;
var hasCaughtError$1 = ReactErrorUtils.hasCaughtError;
var clearCaughtError$1 = ReactErrorUtils.clearCaughtError;
var ReactFiberCommitWork = function (config, captureError) {
var getPublicInstance = config.getPublicInstance,
mutation = config.mutation,
persistence = config.persistence;
var callComponentWillUnmountWithTimer = function (current, instance) {
startPhaseTimer(current, 'componentWillUnmount');
instance.props = current.memoizedProps;
instance.state = current.memoizedState;
instance.componentWillUnmount();
stopPhaseTimer();
};
// Capture errors so they don't interrupt unmounting.
function safelyCallComponentWillUnmount(current, instance) {
{
invokeGuardedCallback$2(null, callComponentWillUnmountWithTimer, null, current, instance);
if (hasCaughtError$1()) {
var unmountError = clearCaughtError$1();
captureError(current, unmountError);
}
}
}
function safelyDetachRef(current) {
var ref = current.ref;
if (ref !== null) {
{
invokeGuardedCallback$2(null, ref, null, null);
if (hasCaughtError$1()) {
var refError = clearCaughtError$1();
captureError(current, refError);
}
}
}
}
function commitLifeCycles(current, finishedWork) {
switch (finishedWork.tag) {
case ClassComponent:
{
var instance = finishedWork.stateNode;
if (finishedWork.effectTag & Update) {
if (current === null) {
startPhaseTimer(finishedWork, 'componentDidMount');
instance.props = finishedWork.memoizedProps;
instance.state = finishedWork.memoizedState;
instance.componentDidMount();
stopPhaseTimer();
} else {
var prevProps = current.memoizedProps;
var prevState = current.memoizedState;
startPhaseTimer(finishedWork, 'componentDidUpdate');
instance.props = finishedWork.memoizedProps;
instance.state = finishedWork.memoizedState;
instance.componentDidUpdate(prevProps, prevState);
stopPhaseTimer();
}
}
var updateQueue = finishedWork.updateQueue;
if (updateQueue !== null) {
commitCallbacks(updateQueue, instance);
}
return;
}
case HostRoot:
{
var _updateQueue = finishedWork.updateQueue;
if (_updateQueue !== null) {
var _instance = finishedWork.child !== null ? finishedWork.child.stateNode : null;
commitCallbacks(_updateQueue, _instance);
}
return;
}
case HostComponent:
{
var _instance2 = finishedWork.stateNode;
// Renderers may schedule work to be done after host components are mounted
// (eg DOM renderer may schedule auto-focus for inputs and form controls).
// These effects should only be committed when components are first mounted,
// aka when there is no current/alternate.
if (current === null && finishedWork.effectTag & Update) {
var type = finishedWork.type;
var props = finishedWork.memoizedProps;
commitMount(_instance2, type, props, finishedWork);
}
return;
}
case HostText:
{
// We have no life-cycles associated with text.
return;
}
case HostPortal:
{
// We have no life-cycles associated with portals.
return;
}
default:
{
invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.');
}
}
}
function commitAttachRef(finishedWork) {
var ref = finishedWork.ref;
if (ref !== null) {
var instance = finishedWork.stateNode;
switch (finishedWork.tag) {
case HostComponent:
ref(getPublicInstance(instance));
break;
default:
ref(instance);
}
}
}
function commitDetachRef(current) {
var currentRef = current.ref;
if (currentRef !== null) {
currentRef(null);
}
}
// User-originating errors (lifecycles and refs) should not interrupt
// deletion, so don't let them throw. Host-originating errors should
// interrupt deletion, so it's okay
function commitUnmount(current) {
if (typeof onCommitUnmount === 'function') {
onCommitUnmount(current);
}
switch (current.tag) {
case ClassComponent:
{
safelyDetachRef(current);
var instance = current.stateNode;
if (typeof instance.componentWillUnmount === 'function') {
safelyCallComponentWillUnmount(current, instance);
}
return;
}
case HostComponent:
{
safelyDetachRef(current);
return;
}
case CallComponent:
{
commitNestedUnmounts(current.stateNode);
return;
}
case HostPortal:
{
// TODO: this is recursive.
// We are also not using this parent because
// the portal will get pushed immediately.
if (enableMutatingReconciler && mutation) {
unmountHostComponents(current);
} else if (enablePersistentReconciler && persistence) {
emptyPortalContainer(current);
}
return;
}
}
}
function commitNestedUnmounts(root) {
// While we're inside a removed host node we don't want to call
// removeChild on the inner nodes because they're removed by the top
// call anyway. We also want to call componentWillUnmount on all
// composites before this host node is removed from the tree. Therefore
var node = root;
while (true) {
commitUnmount(node);
// Visit children because they may contain more composite or host nodes.
// Skip portals because commitUnmount() currently visits them recursively.
if (node.child !== null && (
// If we use mutation we drill down into portals using commitUnmount above.
// If we don't use mutation we drill down into portals here instead.
!mutation || node.tag !== HostPortal)) {
node.child['return'] = node;
node = node.child;
continue;
}
if (node === root) {
return;
}
while (node.sibling === null) {
if (node['return'] === null || node['return'] === root) {
return;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
}
function detachFiber(current) {
// Cut off the return pointers to disconnect it from the tree. Ideally, we
// should clear the child pointer of the parent alternate to let this
// get GC:ed but we don't know which for sure which parent is the current
// one so we'll settle for GC:ing the subtree of this child. This child
// itself will be GC:ed when the parent updates the next time.
current['return'] = null;
current.child = null;
if (current.alternate) {
current.alternate.child = null;
current.alternate['return'] = null;
}
}
if (!mutation) {
var commitContainer = void 0;
if (persistence) {
var replaceContainerChildren = persistence.replaceContainerChildren,
createContainerChildSet = persistence.createContainerChildSet;
var emptyPortalContainer = function (current) {
var portal = current.stateNode;
var containerInfo = portal.containerInfo;
var emptyChildSet = createContainerChildSet(containerInfo);
replaceContainerChildren(containerInfo, emptyChildSet);
};
commitContainer = function (finishedWork) {
switch (finishedWork.tag) {
case ClassComponent:
{
return;
}
case HostComponent:
{
return;
}
case HostText:
{
return;
}
case HostRoot:
case HostPortal:
{
var portalOrRoot = finishedWork.stateNode;
var containerInfo = portalOrRoot.containerInfo,
_pendingChildren = portalOrRoot.pendingChildren;
replaceContainerChildren(containerInfo, _pendingChildren);
return;
}
default:
{
invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.');
}
}
};
} else {
commitContainer = function (finishedWork) {
// Noop
};
}
if (enablePersistentReconciler || enableNoopReconciler) {
return {
commitResetTextContent: function (finishedWork) {},
commitPlacement: function (finishedWork) {},
commitDeletion: function (current) {
// Detach refs and call componentWillUnmount() on the whole subtree.
commitNestedUnmounts(current);
detachFiber(current);
},
commitWork: function (current, finishedWork) {
commitContainer(finishedWork);
},
commitLifeCycles: commitLifeCycles,
commitAttachRef: commitAttachRef,
commitDetachRef: commitDetachRef
};
} else if (persistence) {
invariant(false, 'Persistent reconciler is disabled.');
} else {
invariant(false, 'Noop reconciler is disabled.');
}
}
var commitMount = mutation.commitMount,
commitUpdate = mutation.commitUpdate,
resetTextContent = mutation.resetTextContent,
commitTextUpdate = mutation.commitTextUpdate,
appendChild = mutation.appendChild,
appendChildToContainer = mutation.appendChildToContainer,
insertBefore = mutation.insertBefore,
insertInContainerBefore = mutation.insertInContainerBefore,
removeChild = mutation.removeChild,
removeChildFromContainer = mutation.removeChildFromContainer;
function getHostParentFiber(fiber) {
var parent = fiber['return'];
while (parent !== null) {
if (isHostParent(parent)) {
return parent;
}
parent = parent['return'];
}
invariant(false, 'Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.');
}
function isHostParent(fiber) {
return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal;
}
function getHostSibling(fiber) {
// We're going to search forward into the tree until we find a sibling host
// node. Unfortunately, if multiple insertions are done in a row we have to
// search past them. This leads to exponential search for the next sibling.
var node = fiber;
siblings: while (true) {
// If we didn't find anything, let's try the next sibling.
while (node.sibling === null) {
if (node['return'] === null || isHostParent(node['return'])) {
// If we pop out of the root or hit the parent the fiber we are the
// last sibling.
return null;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
while (node.tag !== HostComponent && node.tag !== HostText) {
// If it is not host node and, we might have a host node inside it.
// Try to search down until we find one.
if (node.effectTag & Placement) {
// If we don't have a child, try the siblings instead.
continue siblings;
}
// If we don't have a child, try the siblings instead.
// We also skip portals because they are not part of this host tree.
if (node.child === null || node.tag === HostPortal) {
continue siblings;
} else {
node.child['return'] = node;
node = node.child;
}
}
// Check if this host node is stable or about to be placed.
if (!(node.effectTag & Placement)) {
// Found it!
return node.stateNode;
}
}
}
function commitPlacement(finishedWork) {
// Recursively insert all host nodes into the parent.
var parentFiber = getHostParentFiber(finishedWork);
var parent = void 0;
var isContainer = void 0;
switch (parentFiber.tag) {
case HostComponent:
parent = parentFiber.stateNode;
isContainer = false;
break;
case HostRoot:
parent = parentFiber.stateNode.containerInfo;
isContainer = true;
break;
case HostPortal:
parent = parentFiber.stateNode.containerInfo;
isContainer = true;
break;
default:
invariant(false, 'Invalid host parent fiber. This error is likely caused by a bug in React. Please file an issue.');
}
if (parentFiber.effectTag & ContentReset) {
// Reset the text content of the parent before doing any insertions
resetTextContent(parent);
// Clear ContentReset from the effect tag
parentFiber.effectTag &= ~ContentReset;
}
var 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.
var node = finishedWork;
while (true) {
if (node.tag === HostComponent || node.tag === HostText) {
if (before) {
if (isContainer) {
insertInContainerBefore(parent, node.stateNode, before);
} else {
insertBefore(parent, node.stateNode, before);
}
} else {
if (isContainer) {
appendChildToContainer(parent, node.stateNode);
} else {
appendChild(parent, node.stateNode);
}
}
} else if (node.tag === HostPortal) {
// 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 !== null) {
node.child['return'] = node;
node = node.child;
continue;
}
if (node === finishedWork) {
return;
}
while (node.sibling === null) {
if (node['return'] === null || node['return'] === finishedWork) {
return;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
}
function unmountHostComponents(current) {
// We only have the top Fiber that was inserted but we need recurse down its
var node = current;
// Each iteration, currentParent is populated with node's host parent if not
// currentParentIsValid.
var currentParentIsValid = false;
var currentParent = void 0;
var currentParentIsContainer = void 0;
while (true) {
if (!currentParentIsValid) {
var parent = node['return'];
findParent: while (true) {
!(parent !== null) ? invariant(false, 'Expected to find a host parent. This error is likely caused by a bug in React. Please file an issue.') : void 0;
switch (parent.tag) {
case HostComponent:
currentParent = parent.stateNode;
currentParentIsContainer = false;
break findParent;
case HostRoot:
currentParent = parent.stateNode.containerInfo;
currentParentIsContainer = true;
break findParent;
case HostPortal:
currentParent = parent.stateNode.containerInfo;
currentParentIsContainer = true;
break findParent;
}
parent = parent['return'];
}
currentParentIsValid = true;
}
if (node.tag === HostComponent || node.tag === HostText) {
commitNestedUnmounts(node);
// After all the children have unmounted, it is now safe to remove the
// node from the tree.
if (currentParentIsContainer) {
removeChildFromContainer(currentParent, node.stateNode);
} else {
removeChild(currentParent, node.stateNode);
}
// Don't visit children because we already visited them.
} else if (node.tag === HostPortal) {
// 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.
currentParent = node.stateNode.containerInfo;
// Visit children because portals might contain host components.
if (node.child !== null) {
node.child['return'] = node;
node = node.child;
continue;
}
} else {
commitUnmount(node);
// Visit children because we may find more host components below.
if (node.child !== null) {
node.child['return'] = node;
node = node.child;
continue;
}
}
if (node === current) {
return;
}
while (node.sibling === null) {
if (node['return'] === null || node['return'] === current) {
return;
}
node = node['return'];
if (node.tag === HostPortal) {
// 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.
currentParentIsValid = false;
}
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
}
function commitDeletion(current) {
// Recursively delete all host nodes from the parent.
// Detach refs and call componentWillUnmount() on the whole subtree.
unmountHostComponents(current);
detachFiber(current);
}
function commitWork(current, finishedWork) {
switch (finishedWork.tag) {
case ClassComponent:
{
return;
}
case HostComponent:
{
var instance = finishedWork.stateNode;
if (instance != null) {
// Commit the work prepared earlier.
var newProps = finishedWork.memoizedProps;
// For hydration we reuse the update path but we treat the oldProps
// as the newProps. The updatePayload will contain the real change in
// this case.
var oldProps = current !== null ? current.memoizedProps : newProps;
var type = finishedWork.type;
// TODO: Type the updateQueue to be specific to host components.
var updatePayload = finishedWork.updateQueue;
finishedWork.updateQueue = null;
if (updatePayload !== null) {
commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork);
}
}
return;
}
case HostText:
{
!(finishedWork.stateNode !== null) ? invariant(false, 'This should have a text node initialized. This error is likely caused by a bug in React. Please file an issue.') : void 0;
var textInstance = finishedWork.stateNode;
var newText = finishedWork.memoizedProps;
// For hydration we reuse the update path but we treat the oldProps
// as the newProps. The updatePayload will contain the real change in
// this case.
var oldText = current !== null ? current.memoizedProps : newText;
commitTextUpdate(textInstance, oldText, newText);
return;
}
case HostRoot:
{
return;
}
default:
{
invariant(false, 'This unit of work tag should not have side-effects. This error is likely caused by a bug in React. Please file an issue.');
}
}
}
function commitResetTextContent(current) {
resetTextContent(current.stateNode);
}
if (enableMutatingReconciler) {
return {
commitResetTextContent: commitResetTextContent,
commitPlacement: commitPlacement,
commitDeletion: commitDeletion,
commitWork: commitWork,
commitLifeCycles: commitLifeCycles,
commitAttachRef: commitAttachRef,
commitDetachRef: commitDetachRef
};
} else {
invariant(false, 'Mutating reconciler is disabled.');
}
};
var NO_CONTEXT = {};
var ReactFiberHostContext = function (config) {
var getChildHostContext = config.getChildHostContext,
getRootHostContext = config.getRootHostContext;
var contextStackCursor = createCursor(NO_CONTEXT);
var contextFiberStackCursor = createCursor(NO_CONTEXT);
var rootInstanceStackCursor = createCursor(NO_CONTEXT);
function requiredContext(c) {
!(c !== NO_CONTEXT) ? invariant(false, 'Expected host context to exist. This error is likely caused by a bug in React. Please file an issue.') : void 0;
return c;
}
function getRootHostContainer() {
var rootInstance = requiredContext(rootInstanceStackCursor.current);
return rootInstance;
}
function pushHostContainer(fiber, nextRootInstance) {
// Push current root instance onto the stack;
// This allows us to reset root when portals are popped.
push(rootInstanceStackCursor, nextRootInstance, fiber);
var nextRootContext = getRootHostContext(nextRootInstance);
// Track the context and the Fiber that provided it.
// This enables us to pop only Fibers that provide unique contexts.
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor, nextRootContext, fiber);
}
function popHostContainer(fiber) {
pop(contextStackCursor, fiber);
pop(contextFiberStackCursor, fiber);
pop(rootInstanceStackCursor, fiber);
}
function getHostContext() {
var context = requiredContext(contextStackCursor.current);
return context;
}
function pushHostContext(fiber) {
var rootInstance = requiredContext(rootInstanceStackCursor.current);
var context = requiredContext(contextStackCursor.current);
var nextContext = getChildHostContext(context, fiber.type, rootInstance);
// Don't push this Fiber's context unless it's unique.
if (context === nextContext) {
return;
}
// Track the context and the Fiber that provided it.
// This enables us to pop only Fibers that provide unique contexts.
push(contextFiberStackCursor, fiber, fiber);
push(contextStackCursor, nextContext, fiber);
}
function popHostContext(fiber) {
// Do not pop unless this Fiber provided the current context.
// pushHostContext() only pushes Fibers that provide unique contexts.
if (contextFiberStackCursor.current !== fiber) {
return;
}
pop(contextStackCursor, fiber);
pop(contextFiberStackCursor, fiber);
}
function resetHostContainer() {
contextStackCursor.current = NO_CONTEXT;
rootInstanceStackCursor.current = NO_CONTEXT;
}
return {
getHostContext: getHostContext,
getRootHostContainer: getRootHostContainer,
popHostContainer: popHostContainer,
popHostContext: popHostContext,
pushHostContainer: pushHostContainer,
pushHostContext: pushHostContext,
resetHostContainer: resetHostContainer
};
};
var ReactFiberHydrationContext = function (config) {
var shouldSetTextContent = config.shouldSetTextContent,
hydration = config.hydration;
// If this doesn't have hydration mode.
if (!hydration) {
return {
enterHydrationState: function () {
return false;
},
resetHydrationState: function () {},
tryToClaimNextHydratableInstance: function () {},
prepareToHydrateHostInstance: function () {
invariant(false, 'Expected prepareToHydrateHostInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.');
},
prepareToHydrateHostTextInstance: function () {
invariant(false, 'Expected prepareToHydrateHostTextInstance() to never be called. This error is likely caused by a bug in React. Please file an issue.');
},
popHydrationState: function (fiber) {
return false;
}
};
}
var canHydrateInstance = hydration.canHydrateInstance,
canHydrateTextInstance = hydration.canHydrateTextInstance,
getNextHydratableSibling = hydration.getNextHydratableSibling,
getFirstHydratableChild = hydration.getFirstHydratableChild,
hydrateInstance = hydration.hydrateInstance,
hydrateTextInstance = hydration.hydrateTextInstance,
didNotMatchHydratedContainerTextInstance = hydration.didNotMatchHydratedContainerTextInstance,
didNotMatchHydratedTextInstance = hydration.didNotMatchHydratedTextInstance,
didNotHydrateContainerInstance = hydration.didNotHydrateContainerInstance,
didNotHydrateInstance = hydration.didNotHydrateInstance,
didNotFindHydratableContainerInstance = hydration.didNotFindHydratableContainerInstance,
didNotFindHydratableContainerTextInstance = hydration.didNotFindHydratableContainerTextInstance,
didNotFindHydratableInstance = hydration.didNotFindHydratableInstance,
didNotFindHydratableTextInstance = hydration.didNotFindHydratableTextInstance;
// The deepest Fiber on the stack involved in a hydration context.
// This may have been an insertion or a hydration.
var hydrationParentFiber = null;
var nextHydratableInstance = null;
var isHydrating = false;
function enterHydrationState(fiber) {
var parentInstance = fiber.stateNode.containerInfo;
nextHydratableInstance = getFirstHydratableChild(parentInstance);
hydrationParentFiber = fiber;
isHydrating = true;
return true;
}
function deleteHydratableInstance(returnFiber, instance) {
{
switch (returnFiber.tag) {
case HostRoot:
didNotHydrateContainerInstance(returnFiber.stateNode.containerInfo, instance);
break;
case HostComponent:
didNotHydrateInstance(returnFiber.type, returnFiber.memoizedProps, returnFiber.stateNode, instance);
break;
}
}
var childToDelete = createFiberFromHostInstanceForDeletion();
childToDelete.stateNode = instance;
childToDelete['return'] = returnFiber;
childToDelete.effectTag = Deletion;
// This might seem like it belongs on progressedFirstDeletion. However,
// these children are not part of the reconciliation list of children.
// Even if we abort and rereconcile the children, that will try to hydrate
// again and the nodes are still in the host tree so these will be
// recreated.
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = childToDelete;
returnFiber.lastEffect = childToDelete;
} else {
returnFiber.firstEffect = returnFiber.lastEffect = childToDelete;
}
}
function insertNonHydratedInstance(returnFiber, fiber) {
fiber.effectTag |= Placement;
{
switch (returnFiber.tag) {
case HostRoot:
{
var parentContainer = returnFiber.stateNode.containerInfo;
switch (fiber.tag) {
case HostComponent:
var type = fiber.type;
var props = fiber.pendingProps;
didNotFindHydratableContainerInstance(parentContainer, type, props);
break;
case HostText:
var text = fiber.pendingProps;
didNotFindHydratableContainerTextInstance(parentContainer, text);
break;
}
break;
}
case HostComponent:
{
var parentType = returnFiber.type;
var parentProps = returnFiber.memoizedProps;
var parentInstance = returnFiber.stateNode;
switch (fiber.tag) {
case HostComponent:
var _type = fiber.type;
var _props = fiber.pendingProps;
didNotFindHydratableInstance(parentType, parentProps, parentInstance, _type, _props);
break;
case HostText:
var _text = fiber.pendingProps;
didNotFindHydratableTextInstance(parentType, parentProps, parentInstance, _text);
break;
}
break;
}
default:
return;
}
}
}
function tryHydrate(fiber, nextInstance) {
switch (fiber.tag) {
case HostComponent:
{
var type = fiber.type;
var props = fiber.pendingProps;
var instance = canHydrateInstance(nextInstance, type, props);
if (instance !== null) {
fiber.stateNode = instance;
return true;
}
return false;
}
case HostText:
{
var text = fiber.pendingProps;
var textInstance = canHydrateTextInstance(nextInstance, text);
if (textInstance !== null) {
fiber.stateNode = textInstance;
return true;
}
return false;
}
default:
return false;
}
}
function tryToClaimNextHydratableInstance(fiber) {
if (!isHydrating) {
return;
}
var nextInstance = nextHydratableInstance;
if (!nextInstance) {
// Nothing to hydrate. Make it an insertion.
insertNonHydratedInstance(hydrationParentFiber, fiber);
isHydrating = false;
hydrationParentFiber = fiber;
return;
}
if (!tryHydrate(fiber, nextInstance)) {
// If we can't hydrate this instance let's try the next one.
// We use this as a heuristic. It's based on intuition and not data so it
// might be flawed or unnecessary.
nextInstance = getNextHydratableSibling(nextInstance);
if (!nextInstance || !tryHydrate(fiber, nextInstance)) {
// Nothing to hydrate. Make it an insertion.
insertNonHydratedInstance(hydrationParentFiber, fiber);
isHydrating = false;
hydrationParentFiber = fiber;
return;
}
// We matched the next one, we'll now assume that the first one was
// superfluous and we'll delete it. Since we can't eagerly delete it
// we'll have to schedule a deletion. To do that, this node needs a dummy
// fiber associated with it.
deleteHydratableInstance(hydrationParentFiber, nextHydratableInstance);
}
hydrationParentFiber = fiber;
nextHydratableInstance = getFirstHydratableChild(nextInstance);
}
function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) {
var instance = fiber.stateNode;
var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber);
// TODO: Type this specific to this type of component.
fiber.updateQueue = updatePayload;
// If the update payload indicates that there is a change or if there
// is a new ref we mark this as an update.
if (updatePayload !== null) {
return true;
}
return false;
}
function prepareToHydrateHostTextInstance(fiber) {
var textInstance = fiber.stateNode;
var textContent = fiber.memoizedProps;
var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber);
{
if (shouldUpdate) {
// We assume that prepareToHydrateHostTextInstance is called in a context where the
// hydration parent is the parent host component of this host text.
var returnFiber = hydrationParentFiber;
if (returnFiber !== null) {
switch (returnFiber.tag) {
case HostRoot:
{
var parentContainer = returnFiber.stateNode.containerInfo;
didNotMatchHydratedContainerTextInstance(parentContainer, textInstance, textContent);
break;
}
case HostComponent:
{
var parentType = returnFiber.type;
var parentProps = returnFiber.memoizedProps;
var parentInstance = returnFiber.stateNode;
didNotMatchHydratedTextInstance(parentType, parentProps, parentInstance, textInstance, textContent);
break;
}
}
}
}
}
return shouldUpdate;
}
function popToNextHostParent(fiber) {
var parent = fiber['return'];
while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot) {
parent = parent['return'];
}
hydrationParentFiber = parent;
}
function popHydrationState(fiber) {
if (fiber !== hydrationParentFiber) {
// We're deeper than the current hydration context, inside an inserted
// tree.
return false;
}
if (!isHydrating) {
// If we're not currently hydrating but we're in a hydration context, then
// we were an insertion and now need to pop up reenter hydration of our
// siblings.
popToNextHostParent(fiber);
isHydrating = true;
return false;
}
var type = fiber.type;
// If we have any remaining hydratable nodes, we need to delete them now.
// We only do this deeper than head and body since they tend to have random
// other nodes in them. We also ignore components with pure text content in
// side of them.
// TODO: Better heuristic.
if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) {
var nextInstance = nextHydratableInstance;
while (nextInstance) {
deleteHydratableInstance(fiber, nextInstance);
nextInstance = getNextHydratableSibling(nextInstance);
}
}
popToNextHostParent(fiber);
nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null;
return true;
}
function resetHydrationState() {
hydrationParentFiber = null;
nextHydratableInstance = null;
isHydrating = false;
}
return {
enterHydrationState: enterHydrationState,
resetHydrationState: resetHydrationState,
tryToClaimNextHydratableInstance: tryToClaimNextHydratableInstance,
prepareToHydrateHostInstance: prepareToHydrateHostInstance,
prepareToHydrateHostTextInstance: prepareToHydrateHostTextInstance,
popHydrationState: popHydrationState
};
};
// This lets us hook into Fiber to debug what it's doing.
// See https://github.com/facebook/react/pull/8033.
// This is not part of the public API, not even for React DevTools.
// You may only inject a debugTool if you work on React Fiber itself.
var ReactFiberInstrumentation = {
debugTool: null
};
var ReactFiberInstrumentation_1 = ReactFiberInstrumentation;
var defaultShowDialog = function (capturedError) {
return true;
};
var showDialog = defaultShowDialog;
function logCapturedError(capturedError) {
var logError = showDialog(capturedError);
// Allow injected showDialog() to prevent default console.error logging.
// This enables renderers like ReactNative to better manage redbox behavior.
if (logError === false) {
return;
}
var error = capturedError.error;
var suppressLogging = error && error.suppressReactErrorLogging;
if (suppressLogging) {
return;
}
{
var componentName = capturedError.componentName,
componentStack = capturedError.componentStack,
errorBoundaryName = capturedError.errorBoundaryName,
errorBoundaryFound = capturedError.errorBoundaryFound,
willRetry = capturedError.willRetry;
var componentNameMessage = componentName ? 'The above error occurred in the <' + componentName + '> component:' : 'The above error occurred in one of your React components:';
var errorBoundaryMessage = void 0;
// errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow.
if (errorBoundaryFound && errorBoundaryName) {
if (willRetry) {
errorBoundaryMessage = 'React will try to recreate this component tree from scratch ' + ('using the error boundary you provided, ' + errorBoundaryName + '.');
} else {
errorBoundaryMessage = 'This error was initially handled by the error boundary ' + errorBoundaryName + '.\n' + 'Recreating the tree from scratch failed so React will unmount the tree.';
}
} else {
errorBoundaryMessage = 'Consider adding an error boundary to your tree to customize error handling behavior.\n' + 'Visit https://fb.me/react-error-boundaries to learn more about error boundaries.';
}
var combinedMessage = '' + componentNameMessage + componentStack + '\n\n' + ('' + errorBoundaryMessage);
// In development, we provide our own message with just the component stack.
// We don't include the original error message and JS stack because the browser
// has already printed it. Even if the application swallows the error, it is still
// displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils.
console.error(combinedMessage);
}
}
var invokeGuardedCallback = ReactErrorUtils.invokeGuardedCallback;
var hasCaughtError = ReactErrorUtils.hasCaughtError;
var clearCaughtError = ReactErrorUtils.clearCaughtError;
{
var didWarnAboutStateTransition = false;
var didWarnSetStateChildContext = false;
var didWarnStateUpdateForUnmountedComponent = {};
var warnAboutUpdateOnUnmounted = function (fiber) {
var componentName = getComponentName(fiber) || 'ReactClass';
if (didWarnStateUpdateForUnmountedComponent[componentName]) {
return;
}
warning(false, 'Can only update a mounted or mounting ' + 'component. This usually means you called setState, replaceState, ' + 'or forceUpdate on an unmounted component. This is a no-op.\n\nPlease ' + 'check the code for the %s component.', componentName);
didWarnStateUpdateForUnmountedComponent[componentName] = true;
};
var warnAboutInvalidUpdates = function (instance) {
switch (ReactDebugCurrentFiber.phase) {
case 'getChildContext':
if (didWarnSetStateChildContext) {
return;
}
warning(false, 'setState(...): Cannot call setState() inside getChildContext()');
didWarnSetStateChildContext = true;
break;
case 'render':
if (didWarnAboutStateTransition) {
return;
}
warning(false, 'Cannot update during an existing state transition (such as within ' + "`render` or another component's constructor). Render methods should " + 'be a pure function of props and state; constructor side-effects are ' + 'an anti-pattern, but can be moved to `componentWillMount`.');
didWarnAboutStateTransition = true;
break;
}
};
}
var ReactFiberScheduler = function (config) {
var hostContext = ReactFiberHostContext(config);
var hydrationContext = ReactFiberHydrationContext(config);
var popHostContainer = hostContext.popHostContainer,
popHostContext = hostContext.popHostContext,
resetHostContainer = hostContext.resetHostContainer;
var _ReactFiberBeginWork = ReactFiberBeginWork(config, hostContext, hydrationContext, scheduleWork, computeExpirationForFiber),
beginWork = _ReactFiberBeginWork.beginWork,
beginFailedWork = _ReactFiberBeginWork.beginFailedWork;
var _ReactFiberCompleteWo = ReactFiberCompleteWork(config, hostContext, hydrationContext),
completeWork = _ReactFiberCompleteWo.completeWork;
var _ReactFiberCommitWork = ReactFiberCommitWork(config, captureError),
commitResetTextContent = _ReactFiberCommitWork.commitResetTextContent,
commitPlacement = _ReactFiberCommitWork.commitPlacement,
commitDeletion = _ReactFiberCommitWork.commitDeletion,
commitWork = _ReactFiberCommitWork.commitWork,
commitLifeCycles = _ReactFiberCommitWork.commitLifeCycles,
commitAttachRef = _ReactFiberCommitWork.commitAttachRef,
commitDetachRef = _ReactFiberCommitWork.commitDetachRef;
var now = config.now,
scheduleDeferredCallback = config.scheduleDeferredCallback,
cancelDeferredCallback = config.cancelDeferredCallback,
useSyncScheduling = config.useSyncScheduling,
prepareForCommit = config.prepareForCommit,
resetAfterCommit = config.resetAfterCommit;
// Represents the current time in ms.
var startTime = now();
var mostRecentCurrentTime = msToExpirationTime(0);
// Represents the expiration time that incoming updates should use. (If this
// is NoWork, use the default strategy: async updates in async mode, sync
// updates in sync mode.)
var expirationContext = NoWork;
var isWorking = false;
// The next work in progress fiber that we're currently working on.
var nextUnitOfWork = null;
var nextRoot = null;
// The time at which we're currently rendering work.
var nextRenderExpirationTime = NoWork;
// The next fiber with an effect that we're currently committing.
var nextEffect = null;
// Keep track of which fibers have captured an error that need to be handled.
// Work is removed from this collection after componentDidCatch is called.
var capturedErrors = null;
// Keep track of which fibers have failed during the current batch of work.
// This is a different set than capturedErrors, because it is not reset until
// the end of the batch. This is needed to propagate errors correctly if a
// subtree fails more than once.
var failedBoundaries = null;
// Error boundaries that captured an error during the current commit.
var commitPhaseBoundaries = null;
var firstUncaughtError = null;
var didFatal = false;
var isCommitting = false;
var isUnmounting = false;
// Used for performance tracking.
var interruptedBy = null;
function resetContextStack() {
// Reset the stack
reset();
// Reset the cursors
resetContext();
resetHostContainer();
}
function commitAllHostEffects() {
while (nextEffect !== null) {
{
ReactDebugCurrentFiber.setCurrentFiber(nextEffect);
}
recordEffect();
var effectTag = nextEffect.effectTag;
if (effectTag & ContentReset) {
commitResetTextContent(nextEffect);
}
if (effectTag & Ref) {
var current = nextEffect.alternate;
if (current !== null) {
commitDetachRef(current);
}
}
// The following switch statement is only concerned about placement,
// updates, and deletions. To avoid needing to add a case for every
// possible bitmap value, we remove the secondary effects from the
// effect tag and switch on that value.
var primaryEffectTag = effectTag & ~(Callback | Err | ContentReset | Ref | PerformedWork);
switch (primaryEffectTag) {
case Placement:
{
commitPlacement(nextEffect);
// Clear the "placement" from effect tag so that we know that this is inserted, before
// any life-cycles like componentDidMount gets called.
// TODO: findDOMNode doesn't rely on this any more but isMounted
// does and isMounted is deprecated anyway so we should be able
// to kill this.
nextEffect.effectTag &= ~Placement;
break;
}
case PlacementAndUpdate:
{
// Placement
commitPlacement(nextEffect);
// Clear the "placement" from effect tag so that we know that this is inserted, before
// any life-cycles like componentDidMount gets called.
nextEffect.effectTag &= ~Placement;
// Update
var _current = nextEffect.alternate;
commitWork(_current, nextEffect);
break;
}
case Update:
{
var _current2 = nextEffect.alternate;
commitWork(_current2, nextEffect);
break;
}
case Deletion:
{
isUnmounting = true;
commitDeletion(nextEffect);
isUnmounting = false;
break;
}
}
nextEffect = nextEffect.nextEffect;
}
{
ReactDebugCurrentFiber.resetCurrentFiber();
}
}
function commitAllLifeCycles() {
while (nextEffect !== null) {
var effectTag = nextEffect.effectTag;
if (effectTag & (Update | Callback)) {
recordEffect();
var current = nextEffect.alternate;
commitLifeCycles(current, nextEffect);
}
if (effectTag & Ref) {
recordEffect();
commitAttachRef(nextEffect);
}
if (effectTag & Err) {
recordEffect();
commitErrorHandling(nextEffect);
}
var next = nextEffect.nextEffect;
// Ensure that we clean these up so that we don't accidentally keep them.
// I'm not actually sure this matters because we can't reset firstEffect
// and lastEffect since they're on every node, not just the effectful
// ones. So we have to clean everything as we reuse nodes anyway.
nextEffect.nextEffect = null;
// Ensure that we reset the effectTag here so that we can rely on effect
// tags to reason about the current life-cycle.
nextEffect = next;
}
}
function commitRoot(finishedWork) {
// We keep track of this so that captureError can collect any boundaries
// that capture an error during the commit phase. The reason these aren't
// local to this function is because errors that occur during cWU are
// captured elsewhere, to prevent the unmount from being interrupted.
isWorking = true;
isCommitting = true;
startCommitTimer();
var root = finishedWork.stateNode;
!(root.current !== finishedWork) ? invariant(false, 'Cannot commit the same tree as before. This is probably a bug related to the return field. This error is likely caused by a bug in React. Please file an issue.') : void 0;
root.isReadyForCommit = false;
// Reset this to null before calling lifecycles
ReactCurrentOwner.current = null;
var firstEffect = void 0;
if (finishedWork.effectTag > PerformedWork) {
// A fiber's effect list consists only of its children, not itself. So if
// the root has an effect, we need to add it to the end of the list. The
// resulting list is the set that would belong to the root's parent, if
// it had one; that is, all the effects in the tree including the root.
if (finishedWork.lastEffect !== null) {
finishedWork.lastEffect.nextEffect = finishedWork;
firstEffect = finishedWork.firstEffect;
} else {
firstEffect = finishedWork;
}
} else {
// There is no effect on the root.
firstEffect = finishedWork.firstEffect;
}
prepareForCommit();
// Commit all the side-effects within a tree. We'll do this in two passes.
// The first pass performs all the host insertions, updates, deletions and
// ref unmounts.
nextEffect = firstEffect;
startCommitHostEffectsTimer();
while (nextEffect !== null) {
var didError = false;
var _error = void 0;
{
invokeGuardedCallback(null, commitAllHostEffects, null);
if (hasCaughtError()) {
didError = true;
_error = clearCaughtError();
}
}
if (didError) {
!(nextEffect !== null) ? invariant(false, 'Should have next effect. This error is likely caused by a bug in React. Please file an issue.') : void 0;
captureError(nextEffect, _error);
// Clean-up
if (nextEffect !== null) {
nextEffect = nextEffect.nextEffect;
}
}
}
stopCommitHostEffectsTimer();
resetAfterCommit();
// The work-in-progress tree is now the current tree. This must come after
// the first pass of the commit phase, so that the previous tree is still
// current during componentWillUnmount, but before the second pass, so that
// the finished work is current during componentDidMount/Update.
root.current = finishedWork;
// In the second pass we'll perform all life-cycles and ref callbacks.
// Life-cycles happen as a separate pass so that all placements, updates,
// and deletions in the entire tree have already been invoked.
// This pass also triggers any renderer-specific initial effects.
nextEffect = firstEffect;
startCommitLifeCyclesTimer();
while (nextEffect !== null) {
var _didError = false;
var _error2 = void 0;
{
invokeGuardedCallback(null, commitAllLifeCycles, null);
if (hasCaughtError()) {
_didError = true;
_error2 = clearCaughtError();
}
}
if (_didError) {
!(nextEffect !== null) ? invariant(false, 'Should have next effect. This error is likely caused by a bug in React. Please file an issue.') : void 0;
captureError(nextEffect, _error2);
if (nextEffect !== null) {
nextEffect = nextEffect.nextEffect;
}
}
}
isCommitting = false;
isWorking = false;
stopCommitLifeCyclesTimer();
stopCommitTimer();
if (typeof onCommitRoot === 'function') {
onCommitRoot(finishedWork.stateNode);
}
if (true && ReactFiberInstrumentation_1.debugTool) {
ReactFiberInstrumentation_1.debugTool.onCommitWork(finishedWork);
}
// If we caught any errors during this commit, schedule their boundaries
// to update.
if (commitPhaseBoundaries) {
commitPhaseBoundaries.forEach(scheduleErrorRecovery);
commitPhaseBoundaries = null;
}
if (firstUncaughtError !== null) {
var _error3 = firstUncaughtError;
firstUncaughtError = null;
onUncaughtError(_error3);
}
var remainingTime = root.current.expirationTime;
if (remainingTime === NoWork) {
capturedErrors = null;
failedBoundaries = null;
}
return remainingTime;
}
function resetExpirationTime(workInProgress, renderTime) {
if (renderTime !== Never && workInProgress.expirationTime === Never) {
// The children of this component are hidden. Don't bubble their
// expiration times.
return;
}
// Check for pending updates.
var newExpirationTime = getUpdateExpirationTime(workInProgress);
// TODO: Calls need to visit stateNode
// Bubble up the earliest expiration time.
var child = workInProgress.child;
while (child !== null) {
if (child.expirationTime !== NoWork && (newExpirationTime === NoWork || newExpirationTime > child.expirationTime)) {
newExpirationTime = child.expirationTime;
}
child = child.sibling;
}
workInProgress.expirationTime = newExpirationTime;
}
function completeUnitOfWork(workInProgress) {
while (true) {
// The current, flushed, state of this fiber is the alternate.
// Ideally nothing should rely on this, but relying on it here
// means that we don't need an additional field on the work in
// progress.
var current = workInProgress.alternate;
{
ReactDebugCurrentFiber.setCurrentFiber(workInProgress);
}
var next = completeWork(current, workInProgress, nextRenderExpirationTime);
{
ReactDebugCurrentFiber.resetCurrentFiber();
}
var returnFiber = workInProgress['return'];
var siblingFiber = workInProgress.sibling;
resetExpirationTime(workInProgress, nextRenderExpirationTime);
if (next !== null) {
stopWorkTimer(workInProgress);
if (true && ReactFiberInstrumentation_1.debugTool) {
ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress);
}
// If completing this work spawned new work, do that next. We'll come
// back here again.
return next;
}
if (returnFiber !== null) {
// Append all the effects of the subtree and this fiber onto the effect
// list of the parent. The completion order of the children affects the
// side-effect order.
if (returnFiber.firstEffect === null) {
returnFiber.firstEffect = workInProgress.firstEffect;
}
if (workInProgress.lastEffect !== null) {
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = workInProgress.firstEffect;
}
returnFiber.lastEffect = workInProgress.lastEffect;
}
// If this fiber had side-effects, we append it AFTER the children's
// side-effects. We can perform certain side-effects earlier if
// needed, by doing multiple passes over the effect list. We don't want
// to schedule our own side-effect on our own list because if end up
// reusing children we'll schedule this effect onto itself since we're
// at the end.
var effectTag = workInProgress.effectTag;
// Skip both NoWork and PerformedWork tags when creating the effect list.
// PerformedWork effect is read by React DevTools but shouldn't be committed.
if (effectTag > PerformedWork) {
if (returnFiber.lastEffect !== null) {
returnFiber.lastEffect.nextEffect = workInProgress;
} else {
returnFiber.firstEffect = workInProgress;
}
returnFiber.lastEffect = workInProgress;
}
}
stopWorkTimer(workInProgress);
if (true && ReactFiberInstrumentation_1.debugTool) {
ReactFiberInstrumentation_1.debugTool.onCompleteWork(workInProgress);
}
if (siblingFiber !== null) {
// If there is more work to do in this returnFiber, do that next.
return siblingFiber;
} else if (returnFiber !== null) {
// If there's no more work in this returnFiber. Complete the returnFiber.
workInProgress = returnFiber;
continue;
} else {
// We've reached the root.
var root = workInProgress.stateNode;
root.isReadyForCommit = true;
return null;
}
}
// Without this explicit null return Flow complains of invalid return type
// TODO Remove the above while(true) loop
// eslint-disable-next-line no-unreachable
return null;
}
function performUnitOfWork(workInProgress) {
// The current, flushed, state of this fiber is the alternate.
// Ideally nothing should rely on this, but relying on it here
// means that we don't need an additional field on the work in
// progress.
var current = workInProgress.alternate;
// See if beginning this work spawns more work.
startWorkTimer(workInProgress);
{
ReactDebugCurrentFiber.setCurrentFiber(workInProgress);
}
var next = beginWork(current, workInProgress, nextRenderExpirationTime);
{
ReactDebugCurrentFiber.resetCurrentFiber();
}
if (true && ReactFiberInstrumentation_1.debugTool) {
ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress);
}
if (next === null) {
// If this doesn't spawn new work, complete the current work.
next = completeUnitOfWork(workInProgress);
}
ReactCurrentOwner.current = null;
return next;
}
function performFailedUnitOfWork(workInProgress) {
// The current, flushed, state of this fiber is the alternate.
// Ideally nothing should rely on this, but relying on it here
// means that we don't need an additional field on the work in
// progress.
var current = workInProgress.alternate;
// See if beginning this work spawns more work.
startWorkTimer(workInProgress);
{
ReactDebugCurrentFiber.setCurrentFiber(workInProgress);
}
var next = beginFailedWork(current, workInProgress, nextRenderExpirationTime);
{
ReactDebugCurrentFiber.resetCurrentFiber();
}
if (true && ReactFiberInstrumentation_1.debugTool) {
ReactFiberInstrumentation_1.debugTool.onBeginWork(workInProgress);
}
if (next === null) {
// If this doesn't spawn new work, complete the current work.
next = completeUnitOfWork(workInProgress);
}
ReactCurrentOwner.current = null;
return next;
}
function workLoop(expirationTime) {
if (capturedErrors !== null) {
// If there are unhandled errors, switch to the slow work loop.
// TODO: How to avoid this check in the fast path? Maybe the renderer
// could keep track of which roots have unhandled errors and call a
// forked version of renderRoot.
slowWorkLoopThatChecksForFailedWork(expirationTime);
return;
}
if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) {
return;
}
if (nextRenderExpirationTime <= mostRecentCurrentTime) {
// Flush all expired work.
while (nextUnitOfWork !== null) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
} else {
// Flush asynchronous work until the deadline runs out of time.
while (nextUnitOfWork !== null && !shouldYield()) {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
}
function slowWorkLoopThatChecksForFailedWork(expirationTime) {
if (nextRenderExpirationTime === NoWork || nextRenderExpirationTime > expirationTime) {
return;
}
if (nextRenderExpirationTime <= mostRecentCurrentTime) {
// Flush all expired work.
while (nextUnitOfWork !== null) {
if (hasCapturedError(nextUnitOfWork)) {
// Use a forked version of performUnitOfWork
nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork);
} else {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
} else {
// Flush asynchronous work until the deadline runs out of time.
while (nextUnitOfWork !== null && !shouldYield()) {
if (hasCapturedError(nextUnitOfWork)) {
// Use a forked version of performUnitOfWork
nextUnitOfWork = performFailedUnitOfWork(nextUnitOfWork);
} else {
nextUnitOfWork = performUnitOfWork(nextUnitOfWork);
}
}
}
}
function renderRootCatchBlock(root, failedWork, boundary, expirationTime) {
// We're going to restart the error boundary that captured the error.
// Conceptually, we're unwinding the stack. We need to unwind the
// context stack, too.
unwindContexts(failedWork, boundary);
// Restart the error boundary using a forked version of
// performUnitOfWork that deletes the boundary's children. The entire
// failed subree will be unmounted. During the commit phase, a special
// lifecycle method is called on the error boundary, which triggers
// a re-render.
nextUnitOfWork = performFailedUnitOfWork(boundary);
// Continue working.
workLoop(expirationTime);
}
function renderRoot(root, expirationTime) {
!!isWorking ? invariant(false, 'renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0;
isWorking = true;
// We're about to mutate the work-in-progress tree. If the root was pending
// commit, it no longer is: we'll need to complete it again.
root.isReadyForCommit = false;
// Check if we're starting from a fresh stack, or if we're resuming from
// previously yielded work.
if (root !== nextRoot || expirationTime !== nextRenderExpirationTime || nextUnitOfWork === null) {
// Reset the stack and start working from the root.
resetContextStack();
nextRoot = root;
nextRenderExpirationTime = expirationTime;
nextUnitOfWork = createWorkInProgress(nextRoot.current, null, expirationTime);
}
startWorkLoopTimer(nextUnitOfWork);
var didError = false;
var error = null;
{
invokeGuardedCallback(null, workLoop, null, expirationTime);
if (hasCaughtError()) {
didError = true;
error = clearCaughtError();
}
}
// An error was thrown during the render phase.
while (didError) {
if (didFatal) {
// This was a fatal error. Don't attempt to recover from it.
firstUncaughtError = error;
break;
}
var failedWork = nextUnitOfWork;
if (failedWork === null) {
// An error was thrown but there's no current unit of work. This can
// happen during the commit phase if there's a bug in the renderer.
didFatal = true;
continue;
}
// "Capture" the error by finding the nearest boundary. If there is no
// error boundary, we use the root.
var boundary = captureError(failedWork, error);
!(boundary !== null) ? invariant(false, 'Should have found an error boundary. This error is likely caused by a bug in React. Please file an issue.') : void 0;
if (didFatal) {
// The error we just captured was a fatal error. This happens
// when the error propagates to the root more than once.
continue;
}
didError = false;
error = null;
{
invokeGuardedCallback(null, renderRootCatchBlock, null, root, failedWork, boundary, expirationTime);
if (hasCaughtError()) {
didError = true;
error = clearCaughtError();
continue;
}
}
// We're finished working. Exit the error loop.
break;
}
var uncaughtError = firstUncaughtError;
// We're done performing work. Time to clean up.
stopWorkLoopTimer(interruptedBy);
interruptedBy = null;
isWorking = false;
didFatal = false;
firstUncaughtError = null;
if (uncaughtError !== null) {
onUncaughtError(uncaughtError);
}
return root.isReadyForCommit ? root.current.alternate : null;
}
// Returns the boundary that captured the error, or null if the error is ignored
function captureError(failedWork, error) {
// It is no longer valid because we exited the user code.
ReactCurrentOwner.current = null;
{
ReactDebugCurrentFiber.resetCurrentFiber();
}
// Search for the nearest error boundary.
var boundary = null;
// Passed to logCapturedError()
var errorBoundaryFound = false;
var willRetry = false;
var errorBoundaryName = null;
// Host containers are a special case. If the failed work itself is a host
// container, then it acts as its own boundary. In all other cases, we
// ignore the work itself and only search through the parents.
if (failedWork.tag === HostRoot) {
boundary = failedWork;
if (isFailedBoundary(failedWork)) {
// If this root already failed, there must have been an error when
// attempting to unmount it. This is a worst-case scenario and
// should only be possible if there's a bug in the renderer.
didFatal = true;
}
} else {
var node = failedWork['return'];
while (node !== null && boundary === null) {
if (node.tag === ClassComponent) {
var instance = node.stateNode;
if (typeof instance.componentDidCatch === 'function') {
errorBoundaryFound = true;
errorBoundaryName = getComponentName(node);
// Found an error boundary!
boundary = node;
willRetry = true;
}
} else if (node.tag === HostRoot) {
// Treat the root like a no-op error boundary
boundary = node;
}
if (isFailedBoundary(node)) {
// This boundary is already in a failed state.
// If we're currently unmounting, that means this error was
// thrown while unmounting a failed subtree. We should ignore
// the error.
if (isUnmounting) {
return null;
}
// If we're in the commit phase, we should check to see if
// this boundary already captured an error during this commit.
// This case exists because multiple errors can be thrown during
// a single commit without interruption.
if (commitPhaseBoundaries !== null && (commitPhaseBoundaries.has(node) || node.alternate !== null && commitPhaseBoundaries.has(node.alternate))) {
// If so, we should ignore this error.
return null;
}
// The error should propagate to the next boundary -— we keep looking.
boundary = null;
willRetry = false;
}
node = node['return'];
}
}
if (boundary !== null) {
// Add to the collection of failed boundaries. This lets us know that
// subsequent errors in this subtree should propagate to the next boundary.
if (failedBoundaries === null) {
failedBoundaries = new Set();
}
failedBoundaries.add(boundary);
// This method is unsafe outside of the begin and complete phases.
// We might be in the commit phase when an error is captured.
// The risk is that the return path from this Fiber may not be accurate.
// That risk is acceptable given the benefit of providing users more context.
var _componentStack = getStackAddendumByWorkInProgressFiber(failedWork);
var _componentName = getComponentName(failedWork);
// Add to the collection of captured errors. This is stored as a global
// map of errors and their component stack location keyed by the boundaries
// that capture them. We mostly use this Map as a Set; it's a Map only to
// avoid adding a field to Fiber to store the error.
if (capturedErrors === null) {
capturedErrors = new Map();
}
var capturedError = {
componentName: _componentName,
componentStack: _componentStack,
error: error,
errorBoundary: errorBoundaryFound ? boundary.stateNode : null,
errorBoundaryFound: errorBoundaryFound,
errorBoundaryName: errorBoundaryName,
willRetry: willRetry
};
capturedErrors.set(boundary, capturedError);
try {
logCapturedError(capturedError);
} catch (e) {
// Prevent cycle if logCapturedError() throws.
// A cycle may still occur if logCapturedError renders a component that throws.
var suppressLogging = e && e.suppressReactErrorLogging;
if (!suppressLogging) {
console.error(e);
}
}
// If we're in the commit phase, defer scheduling an update on the
// boundary until after the commit is complete
if (isCommitting) {
if (commitPhaseBoundaries === null) {
commitPhaseBoundaries = new Set();
}
commitPhaseBoundaries.add(boundary);
} else {
// Otherwise, schedule an update now.
// TODO: Is this actually necessary during the render phase? Is it
// possible to unwind and continue rendering at the same priority,
// without corrupting internal state?
scheduleErrorRecovery(boundary);
}
return boundary;
} else if (firstUncaughtError === null) {
// If no boundary is found, we'll need to throw the error
firstUncaughtError = error;
}
return null;
}
function hasCapturedError(fiber) {
// TODO: capturedErrors should store the boundary instance, to avoid needing
// to check the alternate.
return capturedErrors !== null && (capturedErrors.has(fiber) || fiber.alternate !== null && capturedErrors.has(fiber.alternate));
}
function isFailedBoundary(fiber) {
// TODO: failedBoundaries should store the boundary instance, to avoid
// needing to check the alternate.
return failedBoundaries !== null && (failedBoundaries.has(fiber) || fiber.alternate !== null && failedBoundaries.has(fiber.alternate));
}
function commitErrorHandling(effectfulFiber) {
var capturedError = void 0;
if (capturedErrors !== null) {
capturedError = capturedErrors.get(effectfulFiber);
capturedErrors['delete'](effectfulFiber);
if (capturedError == null) {
if (effectfulFiber.alternate !== null) {
effectfulFiber = effectfulFiber.alternate;
capturedError = capturedErrors.get(effectfulFiber);
capturedErrors['delete'](effectfulFiber);
}
}
}
!(capturedError != null) ? invariant(false, 'No error for given unit of work. This error is likely caused by a bug in React. Please file an issue.') : void 0;
switch (effectfulFiber.tag) {
case ClassComponent:
var instance = effectfulFiber.stateNode;
var info = {
componentStack: capturedError.componentStack
};
// Allow the boundary to handle the error, usually by scheduling
// an update to itself
instance.componentDidCatch(capturedError.error, info);
return;
case HostRoot:
if (firstUncaughtError === null) {
firstUncaughtError = capturedError.error;
}
return;
default:
invariant(false, 'Invalid type of work. This error is likely caused by a bug in React. Please file an issue.');
}
}
function unwindContexts(from, to) {
var node = from;
while (node !== null) {
switch (node.tag) {
case ClassComponent:
popContextProvider(node);
break;
case HostComponent:
popHostContext(node);
break;
case HostRoot:
popHostContainer(node);
break;
case HostPortal:
popHostContainer(node);
break;
}
if (node === to || node.alternate === to) {
stopFailedWorkTimer(node);
break;
} else {
stopWorkTimer(node);
}
node = node['return'];
}
}
function computeAsyncExpiration() {
// Given the current clock time, returns an expiration time. We use rounding
// to batch like updates together.
// Should complete within ~1000ms. 1200ms max.
var currentTime = recalculateCurrentTime();
var expirationMs = 1000;
var bucketSizeMs = 200;
return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs);
}
function computeExpirationForFiber(fiber) {
var expirationTime = void 0;
if (expirationContext !== NoWork) {
// An explicit expiration context was set;
expirationTime = expirationContext;
} else if (isWorking) {
if (isCommitting) {
// Updates that occur during the commit phase should have sync priority
// by default.
expirationTime = Sync;
} else {
// Updates during the render phase should expire at the same time as
// the work that is being rendered.
expirationTime = nextRenderExpirationTime;
}
} else {
// No explicit expiration context was set, and we're not currently
// performing work. Calculate a new expiration time.
if (useSyncScheduling && !(fiber.internalContextTag & AsyncUpdates)) {
// This is a sync update
expirationTime = Sync;
} else {
// This is an async update
expirationTime = computeAsyncExpiration();
}
}
return expirationTime;
}
function scheduleWork(fiber, expirationTime) {
return scheduleWorkImpl(fiber, expirationTime, false);
}
function checkRootNeedsClearing(root, fiber, expirationTime) {
if (!isWorking && root === nextRoot && expirationTime < nextRenderExpirationTime) {
// Restart the root from the top.
if (nextUnitOfWork !== null) {
// This is an interruption. (Used for performance tracking.)
interruptedBy = fiber;
}
nextRoot = null;
nextUnitOfWork = null;
nextRenderExpirationTime = NoWork;
}
}
function scheduleWorkImpl(fiber, expirationTime, isErrorRecovery) {
recordScheduleUpdate();
{
if (!isErrorRecovery && fiber.tag === ClassComponent) {
var instance = fiber.stateNode;
warnAboutInvalidUpdates(instance);
}
}
var node = fiber;
while (node !== null) {
// Walk the parent path to the root and update each node's
// expiration time.
if (node.expirationTime === NoWork || node.expirationTime > expirationTime) {
node.expirationTime = expirationTime;
}
if (node.alternate !== null) {
if (node.alternate.expirationTime === NoWork || node.alternate.expirationTime > expirationTime) {
node.alternate.expirationTime = expirationTime;
}
}
if (node['return'] === null) {
if (node.tag === HostRoot) {
var root = node.stateNode;
checkRootNeedsClearing(root, fiber, expirationTime);
requestWork(root, expirationTime);
checkRootNeedsClearing(root, fiber, expirationTime);
} else {
{
if (!isErrorRecovery && fiber.tag === ClassComponent) {
warnAboutUpdateOnUnmounted(fiber);
}
}
return;
}
}
node = node['return'];
}
}
function scheduleErrorRecovery(fiber) {
scheduleWorkImpl(fiber, Sync, true);
}
function recalculateCurrentTime() {
// Subtract initial time so it fits inside 32bits
var ms = now() - startTime;
mostRecentCurrentTime = msToExpirationTime(ms);
return mostRecentCurrentTime;
}
function deferredUpdates(fn) {
var previousExpirationContext = expirationContext;
expirationContext = computeAsyncExpiration();
try {
return fn();
} finally {
expirationContext = previousExpirationContext;
}
}
function syncUpdates(fn) {
var previousExpirationContext = expirationContext;
expirationContext = Sync;
try {
return fn();
} finally {
expirationContext = previousExpirationContext;
}
}
// TODO: Everything below this is written as if it has been lifted to the
// renderers. I'll do this in a follow-up.
// Linked-list of roots
var firstScheduledRoot = null;
var lastScheduledRoot = null;
var callbackExpirationTime = NoWork;
var callbackID = -1;
var isRendering = false;
var nextFlushedRoot = null;
var nextFlushedExpirationTime = NoWork;
var deadlineDidExpire = false;
var hasUnhandledError = false;
var unhandledError = null;
var deadline = null;
var isBatchingUpdates = false;
var isUnbatchingUpdates = false;
// Use these to prevent an infinite loop of nested updates
var NESTED_UPDATE_LIMIT = 1000;
var nestedUpdateCount = 0;
var timeHeuristicForUnitOfWork = 1;
function scheduleCallbackWithExpiration(expirationTime) {
if (callbackExpirationTime !== NoWork) {
// A callback is already scheduled. Check its expiration time (timeout).
if (expirationTime > callbackExpirationTime) {
// Existing callback has sufficient timeout. Exit.
return;
} else {
// Existing callback has insufficient timeout. Cancel and schedule a
// new one.
cancelDeferredCallback(callbackID);
}
// The request callback timer is already running. Don't start a new one.
} else {
startRequestCallbackTimer();
}
// Compute a timeout for the given expiration time.
var currentMs = now() - startTime;
var expirationMs = expirationTimeToMs(expirationTime);
var timeout = expirationMs - currentMs;
callbackExpirationTime = expirationTime;
callbackID = scheduleDeferredCallback(performAsyncWork, { timeout: timeout });
}
// requestWork is called by the scheduler whenever a root receives an update.
// It's up to the renderer to call renderRoot at some point in the future.
function requestWork(root, expirationTime) {
if (nestedUpdateCount > NESTED_UPDATE_LIMIT) {
invariant(false, 'Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.');
}
// Add the root to the schedule.
// Check if this root is already part of the schedule.
if (root.nextScheduledRoot === null) {
// This root is not already scheduled. Add it.
root.remainingExpirationTime = expirationTime;
if (lastScheduledRoot === null) {
firstScheduledRoot = lastScheduledRoot = root;
root.nextScheduledRoot = root;
} else {
lastScheduledRoot.nextScheduledRoot = root;
lastScheduledRoot = root;
lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
}
} else {
// This root is already scheduled, but its priority may have increased.
var remainingExpirationTime = root.remainingExpirationTime;
if (remainingExpirationTime === NoWork || expirationTime < remainingExpirationTime) {
// Update the priority.
root.remainingExpirationTime = expirationTime;
}
}
if (isRendering) {
// Prevent reentrancy. Remaining work will be scheduled at the end of
// the currently rendering batch.
return;
}
if (isBatchingUpdates) {
// Flush work at the end of the batch.
if (isUnbatchingUpdates) {
// ...unless we're inside unbatchedUpdates, in which case we should
// flush it now.
nextFlushedRoot = root;
nextFlushedExpirationTime = Sync;
performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime);
}
return;
}
// TODO: Get rid of Sync and use current time?
if (expirationTime === Sync) {
performWork(Sync, null);
} else {
scheduleCallbackWithExpiration(expirationTime);
}
}
function findHighestPriorityRoot() {
var highestPriorityWork = NoWork;
var highestPriorityRoot = null;
if (lastScheduledRoot !== null) {
var previousScheduledRoot = lastScheduledRoot;
var root = firstScheduledRoot;
while (root !== null) {
var remainingExpirationTime = root.remainingExpirationTime;
if (remainingExpirationTime === NoWork) {
// This root no longer has work. Remove it from the scheduler.
// TODO: This check is redudant, but Flow is confused by the branch
// below where we set lastScheduledRoot to null, even though we break
// from the loop right after.
!(previousScheduledRoot !== null && lastScheduledRoot !== null) ? invariant(false, 'Should have a previous and last root. This error is likely caused by a bug in React. Please file an issue.') : void 0;
if (root === root.nextScheduledRoot) {
// This is the only root in the list.
root.nextScheduledRoot = null;
firstScheduledRoot = lastScheduledRoot = null;
break;
} else if (root === firstScheduledRoot) {
// This is the first root in the list.
var next = root.nextScheduledRoot;
firstScheduledRoot = next;
lastScheduledRoot.nextScheduledRoot = next;
root.nextScheduledRoot = null;
} else if (root === lastScheduledRoot) {
// This is the last root in the list.
lastScheduledRoot = previousScheduledRoot;
lastScheduledRoot.nextScheduledRoot = firstScheduledRoot;
root.nextScheduledRoot = null;
break;
} else {
previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot;
root.nextScheduledRoot = null;
}
root = previousScheduledRoot.nextScheduledRoot;
} else {
if (highestPriorityWork === NoWork || remainingExpirationTime < highestPriorityWork) {
// Update the priority, if it's higher
highestPriorityWork = remainingExpirationTime;
highestPriorityRoot = root;
}
if (root === lastScheduledRoot) {
break;
}
previousScheduledRoot = root;
root = root.nextScheduledRoot;
}
}
}
// If the next root is the same as the previous root, this is a nested
// update. To prevent an infinite loop, increment the nested update count.
var previousFlushedRoot = nextFlushedRoot;
if (previousFlushedRoot !== null && previousFlushedRoot === highestPriorityRoot) {
nestedUpdateCount++;
} else {
// Reset whenever we switch roots.
nestedUpdateCount = 0;
}
nextFlushedRoot = highestPriorityRoot;
nextFlushedExpirationTime = highestPriorityWork;
}
function performAsyncWork(dl) {
performWork(NoWork, dl);
}
function performWork(minExpirationTime, dl) {
deadline = dl;
// Keep working on roots until there's no more work, or until the we reach
// the deadline.
findHighestPriorityRoot();
if (enableUserTimingAPI && deadline !== null) {
var didExpire = nextFlushedExpirationTime < recalculateCurrentTime();
stopRequestCallbackTimer(didExpire);
}
while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && (minExpirationTime === NoWork || nextFlushedExpirationTime <= minExpirationTime) && !deadlineDidExpire) {
performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime);
// Find the next highest priority work.
findHighestPriorityRoot();
}
// We're done flushing work. Either we ran out of time in this callback,
// or there's no more work left with sufficient priority.
// If we're inside a callback, set this to false since we just completed it.
if (deadline !== null) {
callbackExpirationTime = NoWork;
callbackID = -1;
}
// If there's work left over, schedule a new callback.
if (nextFlushedExpirationTime !== NoWork) {
scheduleCallbackWithExpiration(nextFlushedExpirationTime);
}
// Clean-up.
deadline = null;
deadlineDidExpire = false;
nestedUpdateCount = 0;
if (hasUnhandledError) {
var _error4 = unhandledError;
unhandledError = null;
hasUnhandledError = false;
throw _error4;
}
}
function performWorkOnRoot(root, expirationTime) {
!!isRendering ? invariant(false, 'performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue.') : void 0;
isRendering = true;
// Check if this is async work or sync/expired work.
// TODO: Pass current time as argument to renderRoot, commitRoot
if (expirationTime <= recalculateCurrentTime()) {
// Flush sync work.
var finishedWork = root.finishedWork;
if (finishedWork !== null) {
// This root is already complete. We can commit it.
root.finishedWork = null;
root.remainingExpirationTime = commitRoot(finishedWork);
} else {
root.finishedWork = null;
finishedWork = renderRoot(root, expirationTime);
if (finishedWork !== null) {
// We've completed the root. Commit it.
root.remainingExpirationTime = commitRoot(finishedWork);
}
}
} else {
// Flush async work.
var _finishedWork = root.finishedWork;
if (_finishedWork !== null) {
// This root is already complete. We can commit it.
root.finishedWork = null;
root.remainingExpirationTime = commitRoot(_finishedWork);
} else {
root.finishedWork = null;
_finishedWork = renderRoot(root, expirationTime);
if (_finishedWork !== null) {
// We've completed the root. Check the deadline one more time
// before committing.
if (!shouldYield()) {
// Still time left. Commit the root.
root.remainingExpirationTime = commitRoot(_finishedWork);
} else {
// There's no time left. Mark this root as complete. We'll come
// back and commit it later.
root.finishedWork = _finishedWork;
}
}
}
}
isRendering = false;
}
// When working on async work, the reconciler asks the renderer if it should
// yield execution. For DOM, we implement this with requestIdleCallback.
function shouldYield() {
if (deadline === null) {
return false;
}
if (deadline.timeRemaining() > timeHeuristicForUnitOfWork) {
// Disregard deadline.didTimeout. Only expired work should be flushed
// during a timeout. This path is only hit for non-expired work.
return false;
}
deadlineDidExpire = true;
return true;
}
// TODO: Not happy about this hook. Conceptually, renderRoot should return a
// tuple of (isReadyForCommit, didError, error)
function onUncaughtError(error) {
!(nextFlushedRoot !== null) ? invariant(false, 'Should be working on a root. This error is likely caused by a bug in React. Please file an issue.') : void 0;
// Unschedule this root so we don't work on it again until there's
// another update.
nextFlushedRoot.remainingExpirationTime = NoWork;
if (!hasUnhandledError) {
hasUnhandledError = true;
unhandledError = error;
}
}
// TODO: Batching should be implemented at the renderer level, not inside
// the reconciler.
function batchedUpdates(fn, a) {
var previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return fn(a);
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
if (!isBatchingUpdates && !isRendering) {
performWork(Sync, null);
}
}
}
// TODO: Batching should be implemented at the renderer level, not inside
// the reconciler.
function unbatchedUpdates(fn) {
if (isBatchingUpdates && !isUnbatchingUpdates) {
isUnbatchingUpdates = true;
try {
return fn();
} finally {
isUnbatchingUpdates = false;
}
}
return fn();
}
// TODO: Batching should be implemented at the renderer level, not within
// the reconciler.
function flushSync(fn) {
var previousIsBatchingUpdates = isBatchingUpdates;
isBatchingUpdates = true;
try {
return syncUpdates(fn);
} finally {
isBatchingUpdates = previousIsBatchingUpdates;
!!isRendering ? invariant(false, 'flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering.') : void 0;
performWork(Sync, null);
}
}
return {
computeAsyncExpiration: computeAsyncExpiration,
computeExpirationForFiber: computeExpirationForFiber,
scheduleWork: scheduleWork,
batchedUpdates: batchedUpdates,
unbatchedUpdates: unbatchedUpdates,
flushSync: flushSync,
deferredUpdates: deferredUpdates
};
};
{
var didWarnAboutNestedUpdates = false;
}
// 0 is PROD, 1 is DEV.
// Might add PROFILE later.
function getContextForSubtree(parentComponent) {
if (!parentComponent) {
return emptyObject;
}
var fiber = get(parentComponent);
var parentContext = findCurrentUnmaskedContext(fiber);
return isContextProvider(fiber) ? processChildContext(fiber, parentContext) : parentContext;
}
var ReactFiberReconciler$1 = function (config) {
var getPublicInstance = config.getPublicInstance;
var _ReactFiberScheduler = ReactFiberScheduler(config),
computeAsyncExpiration = _ReactFiberScheduler.computeAsyncExpiration,
computeExpirationForFiber = _ReactFiberScheduler.computeExpirationForFiber,
scheduleWork = _ReactFiberScheduler.scheduleWork,
batchedUpdates = _ReactFiberScheduler.batchedUpdates,
unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates,
flushSync = _ReactFiberScheduler.flushSync,
deferredUpdates = _ReactFiberScheduler.deferredUpdates;
function scheduleTopLevelUpdate(current, element, callback) {
{
if (ReactDebugCurrentFiber.phase === 'render' && ReactDebugCurrentFiber.current !== null && !didWarnAboutNestedUpdates) {
didWarnAboutNestedUpdates = true;
warning(false, 'Render methods should be a pure function of props and state; ' + 'triggering nested component updates from render is not allowed. ' + 'If necessary, trigger nested updates in componentDidUpdate.\n\n' + 'Check the render method of %s.', getComponentName(ReactDebugCurrentFiber.current) || 'Unknown');
}
}
callback = callback === undefined ? null : callback;
{
warning(callback === null || typeof callback === 'function', 'render(...): Expected the last optional `callback` argument to be a ' + 'function. Instead received: %s.', callback);
}
var expirationTime = void 0;
// Check if the top-level element is an async wrapper component. If so,
// treat updates to the root as async. This is a bit weird but lets us
// avoid a separate `renderAsync` API.
if (enableAsyncSubtreeAPI && element != null && element.type != null && element.type.prototype != null && element.type.prototype.unstable_isAsyncReactComponent === true) {
expirationTime = computeAsyncExpiration();
} else {
expirationTime = computeExpirationForFiber(current);
}
var update = {
expirationTime: expirationTime,
partialState: { element: element },
callback: callback,
isReplace: false,
isForced: false,
nextCallback: null,
next: null
};
insertUpdateIntoFiber(current, update);
scheduleWork(current, expirationTime);
}
function findHostInstance(fiber) {
var hostFiber = findCurrentHostFiber(fiber);
if (hostFiber === null) {
return null;
}
return hostFiber.stateNode;
}
return {
createContainer: function (containerInfo, hydrate) {
return createFiberRoot(containerInfo, hydrate);
},
updateContainer: function (element, container, parentComponent, callback) {
// TODO: If this is a nested container, this won't be the root.
var current = container.current;
{
if (ReactFiberInstrumentation_1.debugTool) {
if (current.alternate === null) {
ReactFiberInstrumentation_1.debugTool.onMountContainer(container);
} else if (element === null) {
ReactFiberInstrumentation_1.debugTool.onUnmountContainer(container);
} else {
ReactFiberInstrumentation_1.debugTool.onUpdateContainer(container);
}
}
}
var context = getContextForSubtree(parentComponent);
if (container.context === null) {
container.context = context;
} else {
container.pendingContext = context;
}
scheduleTopLevelUpdate(current, element, callback);
},
batchedUpdates: batchedUpdates,
unbatchedUpdates: unbatchedUpdates,
deferredUpdates: deferredUpdates,
flushSync: flushSync,
getPublicRootInstance: function (container) {
var containerFiber = container.current;
if (!containerFiber.child) {
return null;
}
switch (containerFiber.child.tag) {
case HostComponent:
return getPublicInstance(containerFiber.child.stateNode);
default:
return containerFiber.child.stateNode;
}
},
findHostInstance: findHostInstance,
findHostInstanceWithNoPortals: function (fiber) {
var hostFiber = findCurrentHostFiberWithNoPortals(fiber);
if (hostFiber === null) {
return null;
}
return hostFiber.stateNode;
},
injectIntoDevTools: function (devToolsConfig) {
var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance;
return injectInternals(_assign({}, devToolsConfig, {
findHostInstanceByFiber: function (fiber) {
return findHostInstance(fiber);
},
findFiberByHostInstance: function (instance) {
if (!findFiberByHostInstance) {
// Might not be implemented by the renderer.
return null;
}
return findFiberByHostInstance(instance);
}
}));
}
};
};
var ReactFiberReconciler$2 = Object.freeze({
default: ReactFiberReconciler$1
});
var ReactFiberReconciler$3 = ( ReactFiberReconciler$2 && ReactFiberReconciler$1 ) || ReactFiberReconciler$2;
// TODO: bundle Flow types with the package.
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
var reactReconciler = ReactFiberReconciler$3['default'] ? ReactFiberReconciler$3['default'] : ReactFiberReconciler$3;
var getFiberCurrentPropsFromNode = null;
var getInstanceFromNode = null;
{
}
/**
* Standard/simple iteration through an event's collected dispatches.
*/
/**
* @see executeDispatchesInOrderStopAtTrueImpl
*/
/**
* Execution of a "direct" dispatch - there must be at most one dispatch
* accumulated on the event or it is considered an error. It doesn't really make
* sense for an event with multiple dispatches (bubbled) to keep track of the
* return values at each dispatch execution, but it does tend to make sense when
* dealing with "direct" dispatches.
*
* @return {*} The return value of executing the single dispatch.
*/
/**
* @param {SyntheticEvent} event
* @return {boolean} True iff number of dispatches accumulated is greater than 0.
*/
// Use to restore controlled state after a change event has fired.
var fiberHostComponent = null;
var restoreTarget = null;
var restoreQueue = null;
function restoreStateOfTarget(target) {
// We perform this translation at the end of the event loop so that we
// always receive the correct fiber here
var internalInstance = getInstanceFromNode(target);
if (!internalInstance) {
// Unmounted
return;
}
!(fiberHostComponent && typeof fiberHostComponent.restoreControlledState === 'function') ? invariant(false, 'Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue.') : void 0;
var props = getFiberCurrentPropsFromNode(internalInstance.stateNode);
fiberHostComponent.restoreControlledState(internalInstance.stateNode, internalInstance.type, props);
}
function restoreStateIfNeeded() {
if (!restoreTarget) {
return;
}
var target = restoreTarget;
var queuedTargets = restoreQueue;
restoreTarget = null;
restoreQueue = null;
restoreStateOfTarget(target);
if (queuedTargets) {
for (var i = 0; i < queuedTargets.length; i++) {
restoreStateOfTarget(queuedTargets[i]);
}
}
}
// Used as a way to call batchedUpdates when we don't have a reference to
// the renderer. Such as when we're dispatching events or if third party
// libraries need to call batchedUpdates. Eventually, this API will go away when
// everything is batched by default. We'll then have a similar API to opt-out of
// scheduled work and instead do synchronous work.
// Defaults
var fiberBatchedUpdates = function (fn, bookkeeping) {
return fn(bookkeeping);
};
var isNestingBatched = false;
function batchedUpdates(fn, bookkeeping) {
if (isNestingBatched) {
// If we are currently inside another batch, we need to wait until it
// fully completes before restoring state. Therefore, we add the target to
// a queue of work.
return fiberBatchedUpdates(fn, bookkeeping);
}
isNestingBatched = true;
try {
return fiberBatchedUpdates(fn, bookkeeping);
} finally {
// Here we wait until all updates have propagated, which is important
// when using controlled components within layers:
// https://github.com/facebook/react/issues/1698
// Then we restore state of any controlled component.
isNestingBatched = false;
restoreStateIfNeeded();
}
}
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
var UPDATE_SIGNAL = {};
function getPublicInstance(inst) {
switch (inst.tag) {
case 'INSTANCE':
var _createNodeMock = inst.rootContainerInstance.createNodeMock;
return _createNodeMock({
type: inst.type,
props: inst.props
});
default:
return inst;
}
}
function appendChild(parentInstance, child) {
var index = parentInstance.children.indexOf(child);
if (index !== -1) {
parentInstance.children.splice(index, 1);
}
parentInstance.children.push(child);
}
function insertBefore(parentInstance, child, beforeChild) {
var index = parentInstance.children.indexOf(child);
if (index !== -1) {
parentInstance.children.splice(index, 1);
}
var beforeIndex = parentInstance.children.indexOf(beforeChild);
parentInstance.children.splice(beforeIndex, 0, child);
}
function removeChild(parentInstance, child) {
var index = parentInstance.children.indexOf(child);
parentInstance.children.splice(index, 1);
}
var TestRenderer = reactReconciler({
getRootHostContext: function () {
return emptyObject;
},
getChildHostContext: function () {
return emptyObject;
},
prepareForCommit: function () {
// noop
},
resetAfterCommit: function () {
// noop
},
createInstance: function (type, props, rootContainerInstance, hostContext, internalInstanceHandle) {
return {
type: type,
props: props,
children: [],
rootContainerInstance: rootContainerInstance,
tag: 'INSTANCE'
};
},
appendInitialChild: function (parentInstance, child) {
var index = parentInstance.children.indexOf(child);
if (index !== -1) {
parentInstance.children.splice(index, 1);
}
parentInstance.children.push(child);
},
finalizeInitialChildren: function (testElement, type, props, rootContainerInstance) {
return false;
},
prepareUpdate: function (testElement, type, oldProps, newProps, rootContainerInstance, hostContext) {
return UPDATE_SIGNAL;
},
shouldSetTextContent: function (type, props) {
return false;
},
shouldDeprioritizeSubtree: function (type, props) {
return false;
},
createTextInstance: function (text, rootContainerInstance, hostContext, internalInstanceHandle) {
return {
text: text,
tag: 'TEXT'
};
},
scheduleDeferredCallback: function (fn) {
return setTimeout(fn, 0, { timeRemaining: Infinity });
},
cancelDeferredCallback: function (timeoutID) {
clearTimeout(timeoutID);
},
useSyncScheduling: true,
getPublicInstance: getPublicInstance,
now: function () {
// Test renderer does not use expiration
return 0;
},
mutation: {
commitUpdate: function (instance, updatePayload, type, oldProps, newProps, internalInstanceHandle) {
instance.type = type;
instance.props = newProps;
},
commitMount: function (instance, type, newProps, internalInstanceHandle) {
// noop
},
commitTextUpdate: function (textInstance, oldText, newText) {
textInstance.text = newText;
},
resetTextContent: function (testElement) {
// noop
},
appendChild: appendChild,
appendChildToContainer: appendChild,
insertBefore: insertBefore,
insertInContainerBefore: insertBefore,
removeChild: removeChild,
removeChildFromContainer: removeChild
}
});
var defaultTestOptions = {
createNodeMock: function () {
return null;
}
};
function toJSON(inst) {
switch (inst.tag) {
case 'TEXT':
return inst.text;
case 'INSTANCE':
/* eslint-disable no-unused-vars */
// We don't include the `children` prop in JSON.
// Instead, we will include the actual rendered children.
var _inst$props = inst.props,
_children = _inst$props.children,
_props = _objectWithoutProperties(_inst$props, ['children']);
/* eslint-enable */
var renderedChildren = null;
if (inst.children && inst.children.length) {
renderedChildren = inst.children.map(toJSON);
}
var json = {
type: inst.type,
props: _props,
children: renderedChildren
};
Object.defineProperty(json, '$$typeof', {
value: Symbol['for']('react.test.json')
});
return json;
default:
throw new Error('Unexpected node type in toJSON: ' + inst.tag);
}
}
function nodeAndSiblingsTrees(nodeWithSibling) {
var array = [];
var node = nodeWithSibling;
while (node != null) {
array.push(node);
node = node.sibling;
}
var trees = array.map(toTree);
return trees.length ? trees : null;
}
function hasSiblings(node) {
return node && node.sibling;
}
function toTree(node) {
if (node == null) {
return null;
}
switch (node.tag) {
case HostRoot:
// 3
return toTree(node.child);
case ClassComponent:
return {
nodeType: 'component',
type: node.type,
props: _assign({}, node.memoizedProps),
instance: node.stateNode,
rendered: hasSiblings(node.child) ? nodeAndSiblingsTrees(node.child) : toTree(node.child)
};
case FunctionalComponent:
// 1
return {
nodeType: 'component',
type: node.type,
props: _assign({}, node.memoizedProps),
instance: null,
rendered: hasSiblings(node.child) ? nodeAndSiblingsTrees(node.child) : toTree(node.child)
};
case HostComponent:
// 5
return {
nodeType: 'host',
type: node.type,
props: _assign({}, node.memoizedProps),
instance: null, // TODO: use createNodeMock here somehow?
rendered: nodeAndSiblingsTrees(node.child)
};
case HostText:
// 6
return node.stateNode.text;
default:
invariant(false, 'toTree() does not yet know how to handle nodes with tag=%s', node.tag);
}
}
var fiberToWrapper = new WeakMap();
function wrapFiber(fiber) {
var wrapper = fiberToWrapper.get(fiber);
if (wrapper === undefined && fiber.alternate !== null) {
wrapper = fiberToWrapper.get(fiber.alternate);
}
if (wrapper === undefined) {
wrapper = new ReactTestInstance(fiber);
fiberToWrapper.set(fiber, wrapper);
}
return wrapper;
}
var validWrapperTypes = new Set([FunctionalComponent, ClassComponent, HostComponent]);
var ReactTestInstance = function () {
ReactTestInstance.prototype._currentFiber = function _currentFiber() {
// Throws if this component has been unmounted.
var fiber = findCurrentFiberUsingSlowPath(this._fiber);
!(fiber !== null) ? invariant(false, 'Can\'t read from currently-mounting component. This error is likely caused by a bug in React. Please file an issue.') : void 0;
return fiber;
};
function ReactTestInstance(fiber) {
_classCallCheck(this, ReactTestInstance);
!validWrapperTypes.has(fiber.tag) ? invariant(false, 'Unexpected object passed to ReactTestInstance constructor (tag: %s). This is probably a bug in React.', fiber.tag) : void 0;
this._fiber = fiber;
}
// Custom search functions
ReactTestInstance.prototype.find = function find(predicate) {
return expectOne(this.findAll(predicate, { deep: false }), 'matching custom predicate: ' + predicate.toString());
};
ReactTestInstance.prototype.findByType = function findByType(type) {
return expectOne(this.findAllByType(type, { deep: false }), 'with node type: "' + (type.displayName || type.name) + '"');
};
ReactTestInstance.prototype.findByProps = function findByProps(props) {
return expectOne(this.findAllByProps(props, { deep: false }), 'with props: ' + JSON.stringify(props));
};
ReactTestInstance.prototype.findAll = function findAll(predicate) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
return _findAll(this, predicate, options);
};
ReactTestInstance.prototype.findAllByType = function findAllByType(type) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
return _findAll(this, function (node) {
return node.type === type;
}, options);
};
ReactTestInstance.prototype.findAllByProps = function findAllByProps(props) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
return _findAll(this, function (node) {
return node.props && propsMatch(node.props, props);
}, options);
};
_createClass(ReactTestInstance, [{
key: 'instance',
get: function () {
if (this._fiber.tag === HostComponent) {
return getPublicInstance(this._fiber.stateNode);
} else {
return this._fiber.stateNode;
}
}
}, {
key: 'type',
get: function () {
return this._fiber.type;
}
}, {
key: 'props',
get: function () {
return this._currentFiber().memoizedProps;
}
}, {
key: 'parent',
get: function () {
var parent = this._fiber['return'];
return parent === null || parent.tag === HostRoot ? null : wrapFiber(parent);
}
}, {
key: 'children',
get: function () {
var children = [];
var startingNode = this._currentFiber();
var node = startingNode;
if (node.child === null) {
return children;
}
node.child['return'] = node;
node = node.child;
outer: while (true) {
var descend = false;
switch (node.tag) {
case FunctionalComponent:
case ClassComponent:
case HostComponent:
children.push(wrapFiber(node));
break;
case HostText:
children.push('' + node.memoizedProps);
break;
case Fragment:
descend = true;
break;
default:
invariant(false, 'Unsupported component type %s in test renderer. This is probably a bug in React.', node.tag);
}
if (descend && node.child !== null) {
node.child['return'] = node;
node = node.child;
continue;
}
while (node.sibling === null) {
if (node['return'] === startingNode) {
break outer;
}
node = node['return'];
}
node.sibling['return'] = node['return'];
node = node.sibling;
}
return children;
}
}]);
return ReactTestInstance;
}();
function _findAll(root, predicate, options) {
var deep = options ? options.deep : true;
var results = [];
if (predicate(root)) {
results.push(root);
if (!deep) {
return results;
}
}
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = root.children[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var child = _step.value;
if (typeof child === 'string') {
continue;
}
results.push.apply(results, _findAll(child, predicate, options));
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
return results;
}
function expectOne(all, message) {
if (all.length === 1) {
return all[0];
}
var prefix = all.length === 0 ? 'No instances found ' : 'Expected 1 but found ' + all.length + ' instances ';
throw new Error(prefix + message);
}
function propsMatch(props, filter) {
for (var key in filter) {
if (props[key] !== filter[key]) {
return false;
}
}
return true;
}
var ReactTestRendererFiber = {
create: function (element, options) {
var createNodeMock = defaultTestOptions.createNodeMock;
if (options && typeof options.createNodeMock === 'function') {
createNodeMock = options.createNodeMock;
}
var container = {
children: [],
createNodeMock: createNodeMock,
tag: 'CONTAINER'
};
var root = TestRenderer.createContainer(container, false);
!(root != null) ? invariant(false, 'something went wrong') : void 0;
TestRenderer.updateContainer(element, root, null, null);
var entry = {
root: undefined, // makes flow happy
// we define a 'getter' for 'root' below using 'Object.defineProperty'
toJSON: function () {
if (root == null || root.current == null || container == null) {
return null;
}
if (container.children.length === 0) {
return null;
}
if (container.children.length === 1) {
return toJSON(container.children[0]);
}
return container.children.map(toJSON);
},
toTree: function () {
if (root == null || root.current == null) {
return null;
}
return toTree(root.current);
},
update: function (newElement) {
if (root == null || root.current == null) {
return;
}
TestRenderer.updateContainer(newElement, root, null, null);
},
unmount: function () {
if (root == null || root.current == null) {
return;
}
TestRenderer.updateContainer(null, root, null);
container = null;
root = null;
},
getInstance: function () {
if (root == null || root.current == null) {
return null;
}
return TestRenderer.getPublicRootInstance(root);
}
};
Object.defineProperty(entry, 'root', {
configurable: true,
enumerable: true,
get: function () {
if (root === null || root.current.child === null) {
throw new Error("Can't access .root on unmounted test renderer");
}
return wrapFiber(root.current.child);
}
});
return entry;
},
/* eslint-disable camelcase */
unstable_batchedUpdates: batchedUpdates
};
var ReactTestRenderer = Object.freeze({
default: ReactTestRendererFiber
});
var ReactTestRenderer$1 = ( ReactTestRenderer && ReactTestRendererFiber ) || ReactTestRenderer;
// TODO: decide on the top-level export form.
// This is hacky but makes it work with both Rollup and Jest.
var reactTestRenderer = ReactTestRenderer$1['default'] ? ReactTestRenderer$1['default'] : ReactTestRenderer$1;
module.exports = reactTestRenderer;
})();
}