From 69c77d6492e1465f30cc1463132e18dadc614dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Tue, 20 Mar 2018 17:03:06 -0700 Subject: [PATCH] React sync for revisions ced176e...9d484ed Reviewed By: bvaughn Differential Revision: D7338640 fbshipit-source-id: e2d75d2f1795fb3c37f193d15216951c707711d9 --- Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 2095 ++++++++-------- Libraries/Renderer/ReactFabric-prod.js | 671 +++--- Libraries/Renderer/ReactNativeRenderer-dev.js | 2101 +++++++++-------- .../Renderer/ReactNativeRenderer-prod.js | 681 +++--- Libraries/Renderer/shims/ReactFabric.js | 5 + 6 files changed, 2990 insertions(+), 2565 deletions(-) diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 321055318..7e989de97 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -ced176edb7605a25e916895fd060f3943c647fee \ No newline at end of file +9d484edc4b64160cb335a23a2cb21667fb2cdf4c \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index e485c5621..22c77f2e0 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -25,8 +25,8 @@ var deepDiffer = require("deepDiffer"); var flattenStyle = require("flattenStyle"); var React = require("react"); var emptyObject = require("fbjs/lib/emptyObject"); -var checkPropTypes = require("prop-types/checkPropTypes"); var shallowEqual = require("fbjs/lib/shallowEqual"); +var checkPropTypes = require("prop-types/checkPropTypes"); var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); var FabricUIManager = require("FabricUIManager"); @@ -4134,876 +4134,6 @@ function findCurrentHostFiberWithNoPortals(parent) { return null; } -var valueStack = []; - -var fiberStack = void 0; - -{ - 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 -}; - -var debugRenderPhaseSideEffects = false; -var debugRenderPhaseSideEffectsForStrictMode = false; - -var enableUserTimingAPI = true; -var enableGetDerivedStateFromCatch = false; -var warnAboutDeprecatedLifecycles = false; -var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; - -// React Fabric uses persistent reconciler. -var enableMutatingReconciler = false; -var enableNoopReconciler = false; -var enablePersistentReconciler = true; - -// Only used in www builds. - -// 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 CallComponent: - case ReturnComponent: - case Fragment: - case ContextProvider: - case ContextConsumer: - 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 = void 0; - -{ - 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) { - invariant( - contextStackCursor.cursor == null, - "Unexpected context found on stack. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - - 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) { - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - } - { - 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 Object.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; - invariant( - instance, - "Expected to have an instance by this point. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - - 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 - invariant( - isFiberMounted(fiber) && fiber.tag === ClassComponent, - "Expected subtree parent to be a mounted class component. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - - var node = fiber; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node["return"]; - invariant( - parent, - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - node = parent; - } - return node.stateNode.context; -} - // Max 31 bit integer. The max integer size in V8 for 32-bit systems. // Math.pow(2, 30) - 1 // 0b111111111111111111111111111111 @@ -5441,6 +4571,53 @@ function onCommitUnmount(fiber) { } } +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; +} + /** * Forked from fbjs/warning: * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js @@ -5775,6 +4952,504 @@ var ReactStrictModeWarnings = { }; } +var debugRenderPhaseSideEffects = false; +var debugRenderPhaseSideEffectsForStrictMode = false; + +var enableUserTimingAPI = true; +var enableGetDerivedStateFromCatch = false; +var warnAboutDeprecatedLifecycles = false; +var replayFailedUnitOfWorkWithInvokeGuardedCallback = true; + +// React Fabric uses persistent reconciler. +var enableMutatingReconciler = false; +var enableNoopReconciler = false; +var enablePersistentReconciler = true; + +// Only used in www builds. + +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 CallComponent: + case ReturnComponent: + case Fragment: + case ContextProvider: + case ContextConsumer: + 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 didWarnUpdateInsideUpdate = void 0; { @@ -6172,12 +5847,20 @@ function callGetDerivedStateFromCatch(ctor, capturedValues) { } var ReactFiberClassComponent = function( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState ) { + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged; + // Class component state updater + var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { @@ -8325,71 +8008,6 @@ function cloneChildFibers(current, workInProgress) { newChild.sibling = null; } -var changedBitsStack = []; -var currentValueStack = []; -var stack = []; -var index$1 = -1; - -var rendererSigil = void 0; -{ - // Use this to detect multiple renderers using the same context - rendererSigil = {}; -} - -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - - { - warning( - context._currentRenderer === null || - context._currentRenderer === rendererSigil, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); - context._currentRenderer = rendererSigil; - } -} - -function popProvider(providerFiber) { - { - warning( - index$1 > -1 && providerFiber === stack[index$1], - "Unexpected pop." - ); - } - var changedBits = changedBitsStack[index$1]; - var currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - index$1 -= 1; - var context = providerFiber.type.context; - context._currentValue = currentValue; - context._changedBits = changedBits; -} - -function resetProviderStack() { - for (var i = index$1; i > -1; i--) { - var providerFiber = stack[i]; - var context = providerFiber.type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; - { - context._currentRenderer = null; - } - } - index$1 = -1; -} - var didWarnAboutBadClass = void 0; var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; var didWarnAboutStatelessRefs = void 0; @@ -8403,6 +8021,8 @@ var didWarnAboutStatelessRefs = void 0; var ReactFiberBeginWork = function( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -8411,12 +8031,20 @@ var ReactFiberBeginWork = function( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; var pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer; + var pushProvider = newContext.pushProvider; + var getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider; var enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; var _ReactFiberClassCompo = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -8484,7 +8112,7 @@ var ReactFiberBeginWork = function( function updateFragment(current, workInProgress) { var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (workInProgress.memoizedProps === nextChildren) { @@ -8497,7 +8125,7 @@ var ReactFiberBeginWork = function( function updateMode(current, workInProgress) { var nextChildren = workInProgress.pendingProps.children; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 ( @@ -8526,7 +8154,7 @@ var ReactFiberBeginWork = function( var fn = workInProgress.type; var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 { @@ -8559,7 +8187,7 @@ var ReactFiberBeginWork = function( // 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 hasContext = pushLegacyContextProvider(workInProgress); var shouldUpdate = void 0; if (current === null) { if (workInProgress.stateNode === null) { @@ -8784,7 +8412,7 @@ var ReactFiberBeginWork = function( var nextProps = workInProgress.pendingProps; var prevProps = current !== null ? current.memoizedProps : null; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (memoizedProps === nextProps) { @@ -8919,7 +8547,7 @@ var ReactFiberBeginWork = function( // 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 hasContext = pushLegacyContextProvider(workInProgress); adoptClassInstance(workInProgress, value); mountClassInstance(workInProgress, renderExpirationTime); return finishClassComponent( @@ -8992,7 +8620,7 @@ var ReactFiberBeginWork = function( function updateCallComponent(current, workInProgress, renderExpirationTime) { var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (workInProgress.memoizedProps === nextProps) { @@ -9035,7 +8663,7 @@ var ReactFiberBeginWork = function( ) { pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (workInProgress.memoizedProps === nextChildren) { @@ -9069,6 +8697,10 @@ var ReactFiberBeginWork = function( renderExpirationTime ) { var fiber = workInProgress.child; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber["return"] = workInProgress; + } while (fiber !== null) { var nextFiber = void 0; // Visit this fiber. @@ -9161,7 +8793,7 @@ var ReactFiberBeginWork = function( var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (oldProps === newProps) { @@ -9257,7 +8889,7 @@ var ReactFiberBeginWork = function( var newValue = context._currentValue; var changedBits = context._changedBits; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (changedBits === 0 && oldProps === newProps) { @@ -9354,7 +8986,7 @@ var ReactFiberBeginWork = function( pushHostRootContext(workInProgress); break; case ClassComponent: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case HostPortal: pushHostContainer( @@ -9467,7 +9099,13 @@ var ReactFiberBeginWork = function( }; }; -var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { +var ReactFiberCompleteWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { var createInstance = config.createInstance, createTextInstance = config.createTextInstance, appendInitialChild = config.appendInitialChild, @@ -9479,6 +9117,9 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; var prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -9794,7 +9435,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { return null; case ClassComponent: { // We are leaving this subtree, so pop context if any. - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); // If this component caught an error, schedule an error log effect. var instance = workInProgress.stateNode; @@ -9813,7 +9454,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var fiberRoot = workInProgress.stateNode; if (fiberRoot.pendingContext) { fiberRoot.context = fiberRoot.pendingContext; @@ -10040,11 +9681,16 @@ function createCapturedValue(value, source) { var ReactFiberUnwindWork = function( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; function throwException(returnFiber, sourceFiber, rawValue) { // The source fiber did not complete. @@ -10100,7 +9746,7 @@ var ReactFiberUnwindWork = function( function unwindWork(workInProgress) { switch (workInProgress.tag) { case ClassComponent: { - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; if (effectTag & ShouldCapture) { workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; @@ -10110,7 +9756,7 @@ var ReactFiberUnwindWork = function( } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var _effectTag = workInProgress.effectTag; if (_effectTag & ShouldCapture) { workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; @@ -10132,9 +9778,37 @@ var ReactFiberUnwindWork = function( return null; } } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + return { throwException: throwException, - unwindWork: unwindWork + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork }; }; @@ -10466,7 +10140,7 @@ var ReactFiberCommitWork = function( warning( false, "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or Reacte.createRef().%s", + "Use either a ref-setter function or React.createRef().%s", getComponentName(finishedWork), getStackAddendumByWorkInProgressFiber(finishedWork) ); @@ -10972,9 +10646,12 @@ var ReactFiberCommitWork = function( var NO_CONTEXT = {}; -var ReactFiberHostContext = function(config) { +var ReactFiberHostContext = function(config, stack) { var getChildHostContext = config.getChildHostContext, getRootHostContext = config.getRootHostContext; + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; var contextStackCursor = createCursor(NO_CONTEXT); var contextFiberStackCursor = createCursor(NO_CONTEXT); @@ -11045,19 +10722,13 @@ var ReactFiberHostContext = function(config) { 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 + pushHostContext: pushHostContext }; }; @@ -11427,6 +11098,425 @@ var ReactFiberInstrumentation = { var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var ReactFiberLegacyContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + // 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) { + invariant( + contextStackCursor.cursor == null, + "Unexpected context found on stack. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + + 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) { + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + } + { + 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 Object.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; + invariant( + instance, + "Expected to have an instance by this point. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + + 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 findCurrentUnmaskedContext(fiber) { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + invariant( + isFiberMounted(fiber) && fiber.tag === ClassComponent, + "Expected subtree parent to be a mounted class component. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + + var node = fiber; + while (node.tag !== HostRoot) { + if (isContextProvider(node)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + var parent = node["return"]; + invariant( + parent, + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + node = parent; + } + return node.stateNode.context; + } + + return { + getUnmaskedContext: getUnmaskedContext, + cacheContext: cacheContext, + getMaskedContext: getMaskedContext, + hasContextChanged: hasContextChanged, + isContextConsumer: isContextConsumer, + isContextProvider: isContextProvider, + popContextProvider: popContextProvider, + popTopLevelContextObject: popTopLevelContextObject, + pushTopLevelContextObject: pushTopLevelContextObject, + processChildContext: processChildContext, + pushContextProvider: pushContextProvider, + invalidateContextProvider: invalidateContextProvider, + findCurrentUnmaskedContext: findCurrentUnmaskedContext + }; +}; + +var ReactFiberNewContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var providerCursor = createCursor(null); + var valueCursor = createCursor(null); + var changedBitsCursor = createCursor(0); + + var rendererSigil = void 0; + { + // Use this to detect multiple renderers using the same context + rendererSigil = {}; + } + + function pushProvider(providerFiber) { + var context = providerFiber.type.context; + + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + + { + warning( + context._currentRenderer === null || + context._currentRenderer === rendererSigil, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ); + context._currentRenderer = rendererSigil; + } + } + + function popProvider(providerFiber) { + var changedBits = changedBitsCursor.current; + var currentValue = valueCursor.current; + + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + + var context = providerFiber.type.context; + context._currentValue = currentValue; + context._changedBits = changedBits; + } + + return { + pushProvider: pushProvider, + popProvider: popProvider + }; +}; + +var ReactFiberStack = function() { + var valueStack = []; + + var fiberStack = void 0; + + { + fiberStack = []; + } + + var index = -1; + + function createCursor(defaultValue) { + return { + current: defaultValue + }; + } + + function isEmpty() { + return index === -1; + } + + 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 checkThatStackIsEmpty() { + { + if (index !== -1) { + warning( + false, + "Expected an empty stack. Something was not reset properly." + ); + } + } + } + + function resetStackAfterFatalErrorInDev() { + { + index = -1; + valueStack.length = 0; + fiberStack.length = 0; + } + } + + return { + createCursor: createCursor, + isEmpty: isEmpty, + pop: pop, + push: push, + checkThatStackIsEmpty: checkThatStackIsEmpty, + resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev + }; +}; + var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; var hasCaughtError = ReactErrorUtils.hasCaughtError; var clearCaughtError = ReactErrorUtils.clearCaughtError; @@ -11487,16 +11577,23 @@ var warnAboutInvalidUpdates = void 0; } var ReactFiberScheduler = function(config) { - var hostContext = ReactFiberHostContext(config); + var stack = ReactFiberStack(); + var hostContext = ReactFiberHostContext(config, stack); + var legacyContext = ReactFiberLegacyContext(stack); + var newContext = ReactFiberNewContext(stack); var popHostContext = hostContext.popHostContext, popHostContainer = hostContext.popHostContainer; + var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popLegacyContextProvider = legacyContext.popContextProvider; + var popProvider = newContext.popProvider; var hydrationContext = ReactFiberHydrationContext(config); - var resetHostContainer = hostContext.resetHostContainer; var _ReactFiberBeginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -11506,17 +11603,22 @@ var ReactFiberScheduler = function(config) { var _ReactFiberCompleteWo = ReactFiberCompleteWork( config, hostContext, + legacyContext, + newContext, hydrationContext ), completeWork = _ReactFiberCompleteWo.completeWork; var _ReactFiberUnwindWork = ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ), throwException = _ReactFiberUnwindWork.throwException, - unwindWork = _ReactFiberUnwindWork.unwindWork; + unwindWork = _ReactFiberUnwindWork.unwindWork, + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; var _ReactFiberCommitWork = ReactFiberCommitWork( config, @@ -11585,13 +11687,13 @@ var ReactFiberScheduler = function(config) { switch (failedUnitOfWork.tag) { case HostRoot: popHostContainer(failedUnitOfWork); - popTopLevelContextObject(failedUnitOfWork); + popTopLevelLegacyContextObject(failedUnitOfWork); break; case HostComponent: popHostContext(failedUnitOfWork); break; case ClassComponent: - popContextProvider(failedUnitOfWork); + popLegacyContextProvider(failedUnitOfWork); break; case HostPortal: popHostContainer(failedUnitOfWork); @@ -11611,18 +11713,18 @@ var ReactFiberScheduler = function(config) { }; } - function resetContextStack() { - // Reset the stack - reset(); - // Reset the cursors - resetContext(); - resetHostContainer(); - - // TODO: Unify new context implementation with other stacks - resetProviderStack(); + function resetStack() { + if (nextUnitOfWork !== null) { + var interruptedWork = nextUnitOfWork["return"]; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork["return"]; + } + } { ReactStrictModeWarnings.discardPendingWarnings(); + stack.checkThatStackIsEmpty(); } nextRoot = null; @@ -12146,7 +12248,7 @@ var ReactFiberScheduler = function(config) { nextUnitOfWork === null ) { // Reset the stack and start working from the root. - resetContextStack(); + resetStack(); nextRoot = root; nextRenderExpirationTime = expirationTime; nextUnitOfWork = createWorkInProgress( @@ -12199,6 +12301,9 @@ var ReactFiberScheduler = function(config) { // Yield back to main thread. if (didFatal) { // There was a fatal error. + { + stack.resetStackAfterFatalErrorInDev(); + } return null; } else if (nextUnitOfWork === null) { // We reached the root. @@ -12399,7 +12504,7 @@ var ReactFiberScheduler = function(config) { ) { // This is an interruption. (Used for performance tracking.) interruptedBy = fiber; - resetContextStack(); + resetStack(); } if (nextRoot !== root || !isWorking) { requestWork(root, expirationTime); @@ -12970,7 +13075,8 @@ var ReactFiberScheduler = function(config) { syncUpdates: syncUpdates, interactiveUpdates: interactiveUpdates, flushInteractiveUpdates: flushInteractiveUpdates, - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + legacyContext: legacyContext }; }; @@ -12983,18 +13089,6 @@ var didWarnAboutNestedUpdates = void 0; // 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; @@ -13013,7 +13107,24 @@ var ReactFiberReconciler$1 = function(config) { deferredUpdates = _ReactFiberScheduler.deferredUpdates, syncUpdates = _ReactFiberScheduler.syncUpdates, interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, - flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates; + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, + legacyContext = _ReactFiberScheduler.legacyContext; + + var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + + function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + return isContextProvider(fiber) + ? processChildContext(fiber, parentContext) + : parentContext; + } function scheduleRootUpdate( current, diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index 637481f04..08f112c70 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -1633,136 +1633,6 @@ function findCurrentHostFiberWithNoPortals(parent) { } return null; } -var valueStack = [], - index = -1; -function pop(cursor) { - 0 > index || - ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); -} -function push(cursor, value) { - index++; - valueStack[index] = cursor.current; - cursor.current = value; -} -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - do { - a: switch (workInProgress.tag) { - case 0: - case 1: - case 2: - case 5: - var owner = workInProgress._debugOwner, - source = workInProgress._debugSource; - var JSCompiler_inline_result = getComponentName(workInProgress); - var ownerName = null; - owner && (ownerName = getComponentName(owner)); - owner = source; - JSCompiler_inline_result = - "\n in " + - (JSCompiler_inline_result || "Unknown") + - (owner - ? " (at " + - owner.fileName.replace(/^.*[\\\/]/, "") + - ":" + - owner.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : ""); - break a; - default: - JSCompiler_inline_result = ""; - } - info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; - } while (workInProgress); - return info; -} -new Set(); -var contextStackCursor = { current: emptyObject }, - didPerformWorkStackCursor = { current: !1 }, - previousContext = emptyObject; -function getUnmaskedContext(workInProgress) { - return isContextProvider(workInProgress) - ? previousContext - : contextStackCursor.current; -} -function getMaskedContext(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyObject; - var instance = workInProgress.stateNode; - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext - ) - return instance.__reactInternalMemoizedMaskedChildContext; - var context = {}, - key; - for (key in contextTypes) context[key] = unmaskedContext[key]; - instance && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); - return context; -} -function isContextProvider(fiber) { - return 2 === fiber.tag && null != fiber.type.childContextTypes; -} -function popContextProvider(fiber) { - isContextProvider(fiber) && - (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); -} -function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - null == contextStackCursor.cursor, - "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." - ); - push(contextStackCursor, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); -} -function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode, - childContextTypes = fiber.type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - return Object.assign({}, parentContext, instance); -} -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) return !1; - var instance = workInProgress.stateNode; - instance = - (instance && instance.__reactInternalMemoizedMergedChildContext) || - emptyObject; - previousContext = contextStackCursor.current; - push(contextStackCursor, instance, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return !0; -} -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - if (didChange) { - var mergedContext = processChildContext(workInProgress, previousContext); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - push(contextStackCursor, mergedContext, workInProgress); - } else pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); -} function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; @@ -1929,6 +1799,40 @@ function onCommitRoot(root) { function onCommitUnmount(fiber) { "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); } +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 0: + case 1: + case 2: + case 5: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource; + var JSCompiler_inline_result = getComponentName(workInProgress); + var ownerName = null; + owner && (ownerName = getComponentName(owner)); + owner = source; + JSCompiler_inline_result = + "\n in " + + (JSCompiler_inline_result || "Unknown") + + (owner + ? " (at " + + owner.fileName.replace(/^.*[\\\/]/, "") + + ":" + + owner.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : ""); + break a; + default: + JSCompiler_inline_result = ""; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress["return"]; + } while (workInProgress); + return info; +} +new Set(); function createUpdateQueue(baseState) { return { baseState: baseState, @@ -2084,6 +1988,7 @@ function commitCallbacks(queue, context) { } } function ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -2140,62 +2045,66 @@ function ReactFiberClassComponent( workInProgress.memoizedState ); } - var updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - } - }; + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged, + updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: !0, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: !1, + isForced: !0, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + } + }; return { adoptClassInstance: adoptClassInstance, callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: function(workInProgress, props) { var ctor = workInProgress.type, unmaskedContext = getUnmaskedContext(workInProgress), - needsContext = - 2 === workInProgress.tag && null != workInProgress.type.contextTypes, + needsContext = isContextConsumer(workInProgress), context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; @@ -2212,10 +2121,7 @@ function ReactFiberClassComponent( workInProgress.memoizedState, props )); - needsContext && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + needsContext && cacheContext(workInProgress, unmaskedContext, context); return ctor; }, mountClassInstance: function(workInProgress, renderExpirationTime) { @@ -2300,7 +2206,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldState !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -2389,7 +2295,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldContext !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -3112,34 +3018,12 @@ function ChildReconciler(shouldTrackSideEffects) { }; } var reconcileChildFibers = ChildReconciler(!0), - mountChildFibers = ChildReconciler(!1), - changedBitsStack = [], - currentValueStack = [], - stack = [], - index$1 = -1; -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; -} -function popProvider(providerFiber) { - var changedBits = changedBitsStack[index$1], - currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - --index$1; - providerFiber = providerFiber.type.context; - providerFiber._currentValue = currentValue; - providerFiber._changedBits = changedBits; -} + mountChildFibers = ChildReconciler(!1); function ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -3236,7 +3120,12 @@ function ReactFiberBeginWork( changedBits, renderExpirationTime ) { - for (var fiber = workInProgress.child; null !== fiber; ) { + var fiber = workInProgress.child; + for ( + null !== fiber && (fiber["return"] = workInProgress); + null !== fiber; + + ) { switch (fiber.tag) { case 12: var nextFiber = fiber.stateNode | 0; @@ -3295,7 +3184,7 @@ function ReactFiberBeginWork( var context = workInProgress.type.context, newProps = workInProgress.pendingProps, oldProps = workInProgress.memoizedProps; - if (!didPerformWorkStackCursor.current && oldProps === newProps) + if (!hasLegacyContextChanged() && oldProps === newProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3382,11 +3271,19 @@ function ReactFiberBeginWork( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer, + pushProvider = newContext.pushProvider, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider, enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; config = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, function(workInProgress, nextProps) { @@ -3413,7 +3310,7 @@ function ReactFiberBeginWork( pushHostRootContext(workInProgress); break; case 2: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case 4: pushHostContainer( @@ -3459,7 +3356,7 @@ function ReactFiberBeginWork( workInProgress.memoizedState, props ))), - (props = pushContextProvider(workInProgress)), + (props = pushLegacyContextProvider(workInProgress)), adoptClassInstance(workInProgress, fn), mountClassInstance(workInProgress, renderExpirationTime), (current = finishClassComponent( @@ -3479,7 +3376,7 @@ function ReactFiberBeginWork( return ( (props = workInProgress.type), (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? ((fn = getUnmaskedContext(workInProgress)), (fn = getMaskedContext(workInProgress, fn)), @@ -3495,7 +3392,7 @@ function ReactFiberBeginWork( current ); case 2: - props = pushContextProvider(workInProgress); + props = pushLegacyContextProvider(workInProgress); null === current ? null === workInProgress.stateNode ? (constructClassInstance( @@ -3577,7 +3474,7 @@ function ReactFiberBeginWork( updateQueue = workInProgress.memoizedProps; fn = workInProgress.pendingProps; unmaskedContext = null !== current ? current.memoizedProps : null; - if (!didPerformWorkStackCursor.current && updateQueue === fn) { + if (!hasLegacyContextChanged() && updateQueue === fn) { if ( (updateQueue = workInProgress.mode & 1 && @@ -3619,7 +3516,7 @@ function ReactFiberBeginWork( case 7: return ( (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== props || (props = workInProgress.memoizedProps), (fn = props.children), @@ -3649,8 +3546,7 @@ function ReactFiberBeginWork( workInProgress.stateNode.containerInfo ), (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || - workInProgress.memoizedProps !== props + hasLegacyContextChanged() || workInProgress.memoizedProps !== props ? (null === current ? (workInProgress.child = reconcileChildFibers( workInProgress, @@ -3681,7 +3577,7 @@ function ReactFiberBeginWork( case 10: return ( (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? (reconcileChildren( current, @@ -3699,7 +3595,7 @@ function ReactFiberBeginWork( case 11: return ( (renderExpirationTime = workInProgress.pendingProps.children), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || (null !== renderExpirationTime && workInProgress.memoizedProps !== renderExpirationTime) ? (reconcileChildren( @@ -3729,7 +3625,7 @@ function ReactFiberBeginWork( props = fn._currentValue; var changedBits = fn._changedBits; if ( - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || 0 !== changedBits || updateQueue !== unmaskedContext ) { @@ -3769,7 +3665,13 @@ function ReactFiberBeginWork( } }; } -function ReactFiberCompleteWork(config, hostContext, hydrationContext) { +function ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { function markUpdate(workInProgress) { workInProgress.effectTag |= 4; } @@ -3802,6 +3704,9 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider, prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -3901,7 +3806,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { return null; case 2: return ( - popContextProvider(workInProgress), + popLegacyContextProvider(workInProgress), (current = workInProgress.stateNode), (newProps = workInProgress.updateQueue), null !== newProps && @@ -3914,8 +3819,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { ); case 3: popHostContainer(workInProgress); - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); + popTopLevelLegacyContextObject(workInProgress); newProps = workInProgress.stateNode; newProps.pendingContext && ((newProps.context = newProps.pendingContext), @@ -4099,11 +4003,16 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { } function ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; return { throwException: function(returnFiber, sourceFiber, rawValue) { sourceFiber.effectTag |= 512; @@ -4144,7 +4053,7 @@ function ReactFiberUnwindWork( unwindWork: function(workInProgress) { switch (workInProgress.tag) { case 2: - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; return effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4153,8 +4062,7 @@ function ReactFiberUnwindWork( case 3: return ( popHostContainer(workInProgress), - pop(didPerformWorkStackCursor, workInProgress), - pop(contextStackCursor, workInProgress), + popTopLevelLegacyContextObject(workInProgress), (effectTag = workInProgress.effectTag), effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4170,6 +4078,25 @@ function ReactFiberUnwindWork( default: return null; } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } } }; } @@ -4425,7 +4352,7 @@ function ReactFiberCommitWork( invariant(!1, "Mutating reconciler is disabled."); } var NO_CONTEXT = {}; -function ReactFiberHostContext(config) { +function ReactFiberHostContext(config, stack) { function requiredContext(c) { invariant( c !== NO_CONTEXT, @@ -4434,10 +4361,13 @@ function ReactFiberHostContext(config) { return c; } var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext, - contextStackCursor = { current: NO_CONTEXT }, - contextFiberStackCursor = { current: NO_CONTEXT }, - rootInstanceStackCursor = { current: NO_CONTEXT }; + getRootHostContext = config.getRootHostContext; + config = stack.createCursor; + var push = stack.push, + pop = stack.pop, + contextStackCursor = config(NO_CONTEXT), + contextFiberStackCursor = config(NO_CONTEXT), + rootInstanceStackCursor = config(NO_CONTEXT); return { getHostContext: function() { return requiredContext(contextStackCursor.current); @@ -4467,10 +4397,6 @@ function ReactFiberHostContext(config) { context !== rootInstance && (push(contextFiberStackCursor, fiber, fiber), push(contextStackCursor, rootInstance, fiber)); - }, - resetHostContainer: function() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; } }; } @@ -4630,22 +4556,198 @@ function ReactFiberHydrationContext(config) { } }; } -function ReactFiberScheduler(config) { - function resetContextStack() { - for (; -1 < index; ) (valueStack[index] = null), index--; +function ReactFiberLegacyContext(stack) { + function cacheContext(workInProgress, unmaskedContext, maskedContext) { + workInProgress = workInProgress.stateNode; + workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; + } + function isContextProvider(fiber) { + return 2 === fiber.tag && null != fiber.type.childContextTypes; + } + function processChildContext(fiber, parentContext) { + var instance = fiber.stateNode, + childContextTypes = fiber.type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + return Object.assign({}, parentContext, instance); + } + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + contextStackCursor = createCursor(emptyObject), + didPerformWorkStackCursor = createCursor(!1), previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = !1; - resetHostContainer(); - for (var i = index$1; -1 < i; i--) { - var context = stack[i].type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; + return { + getUnmaskedContext: function(workInProgress) { + return isContextProvider(workInProgress) + ? previousContext + : contextStackCursor.current; + }, + cacheContext: cacheContext, + getMaskedContext: function(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && cacheContext(workInProgress, unmaskedContext, context); + return context; + }, + hasContextChanged: function() { + return didPerformWorkStackCursor.current; + }, + isContextConsumer: function(fiber) { + return 2 === fiber.tag && null != fiber.type.contextTypes; + }, + isContextProvider: isContextProvider, + popContextProvider: function(fiber) { + isContextProvider(fiber) && + (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); + }, + popTopLevelContextObject: function(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + }, + pushTopLevelContextObject: function(fiber, context, didChange) { + invariant( + null == contextStackCursor.cursor, + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); + }, + processChildContext: processChildContext, + pushContextProvider: function(workInProgress) { + if (!isContextProvider(workInProgress)) return !1; + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; + }, + invalidateContextProvider: function(workInProgress, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + if (didChange) { + var mergedContext = processChildContext( + workInProgress, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + push(contextStackCursor, mergedContext, workInProgress); + } else pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + }, + findCurrentUnmaskedContext: function(fiber) { + for ( + invariant( + 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + 3 !== fiber.tag; + + ) { + if (isContextProvider(fiber)) + return fiber.stateNode.__reactInternalMemoizedMergedChildContext; + fiber = fiber["return"]; + invariant( + fiber, + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + return fiber.stateNode.context; } - index$1 = -1; + }; +} +function ReactFiberNewContext(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + providerCursor = createCursor(null), + valueCursor = createCursor(null), + changedBitsCursor = createCursor(0); + return { + pushProvider: function(providerFiber) { + var context = providerFiber.type.context; + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + }, + popProvider: function(providerFiber) { + var changedBits = changedBitsCursor.current, + currentValue = valueCursor.current; + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + providerFiber = providerFiber.type.context; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; + } + }; +} +function ReactFiberStack() { + var valueStack = [], + index = -1; + return { + createCursor: function(defaultValue) { + return { current: defaultValue }; + }, + isEmpty: function() { + return -1 === index; + }, + pop: function(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), + (valueStack[index] = null), + index--); + }, + push: function(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; + }, + checkThatStackIsEmpty: function() {}, + resetStackAfterFatalErrorInDev: function() {} + }; +} +function ReactFiberScheduler(config) { + function resetStack() { + if (null !== nextUnitOfWork) + for ( + var interruptedWork = nextUnitOfWork["return"]; + null !== interruptedWork; + + ) + unwindInterruptedWork(interruptedWork), + (interruptedWork = interruptedWork["return"]); nextRoot = null; nextRenderExpirationTime = 0; nextUnitOfWork = null; @@ -4751,7 +4853,7 @@ function ReactFiberScheduler(config) { root !== nextRoot || null === nextUnitOfWork ) - resetContextStack(), + resetStack(), (nextRoot = root), (nextRenderExpirationTime = expirationTime), (nextUnitOfWork = createWorkInProgress( @@ -4881,7 +4983,7 @@ function ReactFiberScheduler(config) { !isWorking && 0 !== nextRenderExpirationTime && expirationTime < nextRenderExpirationTime && - resetContextStack(); + resetStack(); (nextRoot === root && isWorking) || requestWork(root, expirationTime); nestedUpdateCount > NESTED_UPDATE_LIMIT && @@ -5225,25 +5327,37 @@ function ReactFiberScheduler(config) { nextFlushedRoot.remainingExpirationTime = 0; hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); } - var hostContext = ReactFiberHostContext(config), - hydrationContext = ReactFiberHydrationContext(config), - resetHostContainer = hostContext.resetHostContainer, + var stack = ReactFiberStack(), + hostContext = ReactFiberHostContext(config, stack), + legacyContext = ReactFiberLegacyContext(stack); + stack = ReactFiberNewContext(stack); + var hydrationContext = ReactFiberHydrationContext(config), beginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + stack, hydrationContext, scheduleWork, computeExpirationForFiber ).beginWork, - completeWork = ReactFiberCompleteWork(config, hostContext, hydrationContext) - .completeWork; + completeWork = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext + ).completeWork; hostContext = ReactFiberUnwindWork( hostContext, + legacyContext, + stack, scheduleWork, isAlreadyFailedLegacyErrorBoundary ); var throwException = hostContext.throwException, - unwindWork = hostContext.unwindWork; + unwindWork = hostContext.unwindWork, + unwindInterruptedWork = hostContext.unwindInterruptedWork; hostContext = ReactFiberCommitWork( config, onCommitPhaseError, @@ -5402,7 +5516,8 @@ function ReactFiberScheduler(config) { result <= lastUniqueAsyncExpiration && (result = lastUniqueAsyncExpiration + 1); return (lastUniqueAsyncExpiration = result); - } + }, + legacyContext: legacyContext }; } function ReactFiberReconciler$1(config) { @@ -5417,27 +5532,7 @@ function ReactFiberReconciler$1(config) { currentTime = container.current; if (parentComponent) { parentComponent = parentComponent._reactInternalFiber; - var parentContext; - b: { - invariant( - 2 === isFiberMountedImpl(parentComponent) && - 2 === parentComponent.tag, - "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." - ); - for (parentContext = parentComponent; 3 !== parentContext.tag; ) { - if (isContextProvider(parentContext)) { - parentContext = - parentContext.stateNode.__reactInternalMemoizedMergedChildContext; - break b; - } - parentContext = parentContext["return"]; - invariant( - parentContext, - "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." - ); - } - parentContext = parentContext.stateNode.context; - } + var parentContext = findCurrentUnmaskedContext(parentComponent); parentComponent = isContextProvider(parentComponent) ? processChildContext(parentComponent, parentContext) : parentContext; @@ -5466,7 +5561,11 @@ function ReactFiberReconciler$1(config) { config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, computeExpirationForFiber = config.computeExpirationForFiber, - scheduleWork = config.scheduleWork; + scheduleWork = config.scheduleWork, + legacyContext = config.legacyContext, + findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; return { createContainer: function(containerInfo, isAsync, hydrate) { isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index d54c9f31c..8ea8bcf85 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -26,9 +26,9 @@ var deepDiffer = require("deepDiffer"); var flattenStyle = require("flattenStyle"); var React = require("react"); var emptyObject = require("fbjs/lib/emptyObject"); -var checkPropTypes = require("prop-types/checkPropTypes"); var shallowEqual = require("fbjs/lib/shallowEqual"); var ExceptionsManager = require("ExceptionsManager"); +var checkPropTypes = require("prop-types/checkPropTypes"); var deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); var invokeGuardedCallback = function(name, func, context, a, b, c, d, e, f) { @@ -4389,879 +4389,6 @@ function findCurrentHostFiberWithNoPortals(parent) { return null; } -var valueStack = []; - -var fiberStack = void 0; - -{ - 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 -}; - -// Re-export dynamic flags from the fbsource version. -var _require = require("ReactFeatureFlags"); - -var enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch; -var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; -var debugRenderPhaseSideEffectsForStrictMode = - _require.debugRenderPhaseSideEffectsForStrictMode; -var warnAboutDeprecatedLifecycles = _require.warnAboutDeprecatedLifecycles; -var replayFailedUnitOfWorkWithInvokeGuardedCallback = - _require.replayFailedUnitOfWorkWithInvokeGuardedCallback; - -var enableUserTimingAPI = true; -var enableMutatingReconciler = true; -var enableNoopReconciler = false; -var enablePersistentReconciler = false; - -// Only used in www builds. - -// 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 CallComponent: - case ReturnComponent: - case Fragment: - case ContextProvider: - case ContextConsumer: - 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 = void 0; - -{ - 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) { - invariant( - contextStackCursor.cursor == null, - "Unexpected context found on stack. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - - 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) { - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - } - { - 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 Object.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; - invariant( - instance, - "Expected to have an instance by this point. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - - 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 - invariant( - isFiberMounted(fiber) && fiber.tag === ClassComponent, - "Expected subtree parent to be a mounted class component. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - - var node = fiber; - while (node.tag !== HostRoot) { - if (isContextProvider(node)) { - return node.stateNode.__reactInternalMemoizedMergedChildContext; - } - var parent = node["return"]; - invariant( - parent, - "Found unexpected detached subtree parent. " + - "This error is likely caused by a bug in React. Please file an issue." - ); - node = parent; - } - return node.stateNode.context; -} - // Max 31 bit integer. The max integer size in V8 for 32-bit systems. // Math.pow(2, 30) - 1 // 0b111111111111111111111111111111 @@ -5699,6 +4826,53 @@ function onCommitUnmount(fiber) { } } +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; +} + /** * Forked from fbjs/warning: * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js @@ -6033,6 +5207,507 @@ var ReactStrictModeWarnings = { }; } +// Re-export dynamic flags from the fbsource version. +var _require = require("ReactFeatureFlags"); + +var enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch; +var debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects; +var debugRenderPhaseSideEffectsForStrictMode = + _require.debugRenderPhaseSideEffectsForStrictMode; +var warnAboutDeprecatedLifecycles = _require.warnAboutDeprecatedLifecycles; +var replayFailedUnitOfWorkWithInvokeGuardedCallback = + _require.replayFailedUnitOfWorkWithInvokeGuardedCallback; + +var enableUserTimingAPI = true; +var enableMutatingReconciler = true; +var enableNoopReconciler = false; +var enablePersistentReconciler = false; + +// Only used in www builds. + +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 CallComponent: + case ReturnComponent: + case Fragment: + case ContextProvider: + case ContextConsumer: + 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 didWarnUpdateInsideUpdate = void 0; { @@ -6430,12 +6105,20 @@ function callGetDerivedStateFromCatch(ctor, capturedValues) { } var ReactFiberClassComponent = function( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, memoizeState ) { + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged; + // Class component state updater + var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { @@ -8583,71 +8266,6 @@ function cloneChildFibers(current, workInProgress) { newChild.sibling = null; } -var changedBitsStack = []; -var currentValueStack = []; -var stack = []; -var index$1 = -1; - -var rendererSigil = void 0; -{ - // Use this to detect multiple renderers using the same context - rendererSigil = {}; -} - -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; - - { - warning( - context._currentRenderer === null || - context._currentRenderer === rendererSigil, - "Detected multiple renderers concurrently rendering the " + - "same context provider. This is currently unsupported." - ); - context._currentRenderer = rendererSigil; - } -} - -function popProvider(providerFiber) { - { - warning( - index$1 > -1 && providerFiber === stack[index$1], - "Unexpected pop." - ); - } - var changedBits = changedBitsStack[index$1]; - var currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - index$1 -= 1; - var context = providerFiber.type.context; - context._currentValue = currentValue; - context._changedBits = changedBits; -} - -function resetProviderStack() { - for (var i = index$1; i > -1; i--) { - var providerFiber = stack[i]; - var context = providerFiber.type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; - { - context._currentRenderer = null; - } - } - index$1 = -1; -} - var didWarnAboutBadClass = void 0; var didWarnAboutGetDerivedStateOnFunctionalComponent = void 0; var didWarnAboutStatelessRefs = void 0; @@ -8661,6 +8279,8 @@ var didWarnAboutStatelessRefs = void 0; var ReactFiberBeginWork = function( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -8669,12 +8289,20 @@ var ReactFiberBeginWork = function( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree; var pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer; + var pushProvider = newContext.pushProvider; + var getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider; var enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; var _ReactFiberClassCompo = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -8742,7 +8370,7 @@ var ReactFiberBeginWork = function( function updateFragment(current, workInProgress) { var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (workInProgress.memoizedProps === nextChildren) { @@ -8755,7 +8383,7 @@ var ReactFiberBeginWork = function( function updateMode(current, workInProgress) { var nextChildren = workInProgress.pendingProps.children; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 ( @@ -8784,7 +8412,7 @@ var ReactFiberBeginWork = function( var fn = workInProgress.type; var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 { @@ -8817,7 +8445,7 @@ var ReactFiberBeginWork = function( // 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 hasContext = pushLegacyContextProvider(workInProgress); var shouldUpdate = void 0; if (current === null) { if (workInProgress.stateNode === null) { @@ -9042,7 +8670,7 @@ var ReactFiberBeginWork = function( var nextProps = workInProgress.pendingProps; var prevProps = current !== null ? current.memoizedProps : null; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (memoizedProps === nextProps) { @@ -9177,7 +8805,7 @@ var ReactFiberBeginWork = function( // 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 hasContext = pushLegacyContextProvider(workInProgress); adoptClassInstance(workInProgress, value); mountClassInstance(workInProgress, renderExpirationTime); return finishClassComponent( @@ -9250,7 +8878,7 @@ var ReactFiberBeginWork = function( function updateCallComponent(current, workInProgress, renderExpirationTime) { var nextProps = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (workInProgress.memoizedProps === nextProps) { @@ -9293,7 +8921,7 @@ var ReactFiberBeginWork = function( ) { pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); var nextChildren = workInProgress.pendingProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (workInProgress.memoizedProps === nextChildren) { @@ -9327,6 +8955,10 @@ var ReactFiberBeginWork = function( renderExpirationTime ) { var fiber = workInProgress.child; + if (fiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + fiber["return"] = workInProgress; + } while (fiber !== null) { var nextFiber = void 0; // Visit this fiber. @@ -9419,7 +9051,7 @@ var ReactFiberBeginWork = function( var newProps = workInProgress.pendingProps; var oldProps = workInProgress.memoizedProps; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (oldProps === newProps) { @@ -9515,7 +9147,7 @@ var ReactFiberBeginWork = function( var newValue = context._currentValue; var changedBits = context._changedBits; - if (hasContextChanged()) { + if (hasLegacyContextChanged()) { // 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 (changedBits === 0 && oldProps === newProps) { @@ -9612,7 +9244,7 @@ var ReactFiberBeginWork = function( pushHostRootContext(workInProgress); break; case ClassComponent: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case HostPortal: pushHostContainer( @@ -9725,7 +9357,13 @@ var ReactFiberBeginWork = function( }; }; -var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { +var ReactFiberCompleteWork = function( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { var createInstance = config.createInstance, createTextInstance = config.createTextInstance, appendInitialChild = config.appendInitialChild, @@ -9737,6 +9375,9 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; var prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -10052,7 +9693,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { return null; case ClassComponent: { // We are leaving this subtree, so pop context if any. - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); // If this component caught an error, schedule an error log effect. var instance = workInProgress.stateNode; @@ -10071,7 +9712,7 @@ var ReactFiberCompleteWork = function(config, hostContext, hydrationContext) { } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var fiberRoot = workInProgress.stateNode; if (fiberRoot.pendingContext) { fiberRoot.context = fiberRoot.pendingContext; @@ -10298,11 +9939,16 @@ function createCapturedValue(value, source) { var ReactFiberUnwindWork = function( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, popHostContext = hostContext.popHostContext; + var popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject; + var popProvider = newContext.popProvider; function throwException(returnFiber, sourceFiber, rawValue) { // The source fiber did not complete. @@ -10358,7 +10004,7 @@ var ReactFiberUnwindWork = function( function unwindWork(workInProgress) { switch (workInProgress.tag) { case ClassComponent: { - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; if (effectTag & ShouldCapture) { workInProgress.effectTag = (effectTag & ~ShouldCapture) | DidCapture; @@ -10368,7 +10014,7 @@ var ReactFiberUnwindWork = function( } case HostRoot: { popHostContainer(workInProgress); - popTopLevelContextObject(workInProgress); + popTopLevelLegacyContextObject(workInProgress); var _effectTag = workInProgress.effectTag; if (_effectTag & ShouldCapture) { workInProgress.effectTag = (_effectTag & ~ShouldCapture) | DidCapture; @@ -10390,9 +10036,37 @@ var ReactFiberUnwindWork = function( return null; } } + + function unwindInterruptedWork(interruptedWork) { + switch (interruptedWork.tag) { + case ClassComponent: { + popLegacyContextProvider(interruptedWork); + break; + } + case HostRoot: { + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + } + case HostComponent: { + popHostContext(interruptedWork); + break; + } + case HostPortal: + popHostContainer(interruptedWork); + break; + case ContextProvider: + popProvider(interruptedWork); + break; + default: + break; + } + } + return { throwException: throwException, - unwindWork: unwindWork + unwindWork: unwindWork, + unwindInterruptedWork: unwindInterruptedWork }; }; @@ -10758,7 +10432,7 @@ var ReactFiberCommitWork = function( warning( false, "Unexpected ref object provided for %s. " + - "Use either a ref-setter function or Reacte.createRef().%s", + "Use either a ref-setter function or React.createRef().%s", getComponentName(finishedWork), getStackAddendumByWorkInProgressFiber(finishedWork) ); @@ -11264,9 +10938,12 @@ var ReactFiberCommitWork = function( var NO_CONTEXT = {}; -var ReactFiberHostContext = function(config) { +var ReactFiberHostContext = function(config, stack) { var getChildHostContext = config.getChildHostContext, getRootHostContext = config.getRootHostContext; + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; var contextStackCursor = createCursor(NO_CONTEXT); var contextFiberStackCursor = createCursor(NO_CONTEXT); @@ -11337,19 +11014,13 @@ var ReactFiberHostContext = function(config) { 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 + pushHostContext: pushHostContext }; }; @@ -11719,6 +11390,425 @@ var ReactFiberInstrumentation = { var ReactFiberInstrumentation_1 = ReactFiberInstrumentation; +var warnedAboutMissingGetChildContext = void 0; + +{ + warnedAboutMissingGetChildContext = {}; +} + +var ReactFiberLegacyContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + // 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) { + invariant( + contextStackCursor.cursor == null, + "Unexpected context found on stack. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + + 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) { + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + } + { + 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 Object.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; + invariant( + instance, + "Expected to have an instance by this point. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + + 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 findCurrentUnmaskedContext(fiber) { + // Currently this is only used with renderSubtreeIntoContainer; not sure if it + // makes sense elsewhere + invariant( + isFiberMounted(fiber) && fiber.tag === ClassComponent, + "Expected subtree parent to be a mounted class component. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + + var node = fiber; + while (node.tag !== HostRoot) { + if (isContextProvider(node)) { + return node.stateNode.__reactInternalMemoizedMergedChildContext; + } + var parent = node["return"]; + invariant( + parent, + "Found unexpected detached subtree parent. " + + "This error is likely caused by a bug in React. Please file an issue." + ); + node = parent; + } + return node.stateNode.context; + } + + return { + getUnmaskedContext: getUnmaskedContext, + cacheContext: cacheContext, + getMaskedContext: getMaskedContext, + hasContextChanged: hasContextChanged, + isContextConsumer: isContextConsumer, + isContextProvider: isContextProvider, + popContextProvider: popContextProvider, + popTopLevelContextObject: popTopLevelContextObject, + pushTopLevelContextObject: pushTopLevelContextObject, + processChildContext: processChildContext, + pushContextProvider: pushContextProvider, + invalidateContextProvider: invalidateContextProvider, + findCurrentUnmaskedContext: findCurrentUnmaskedContext + }; +}; + +var ReactFiberNewContext = function(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop; + + var providerCursor = createCursor(null); + var valueCursor = createCursor(null); + var changedBitsCursor = createCursor(0); + + var rendererSigil = void 0; + { + // Use this to detect multiple renderers using the same context + rendererSigil = {}; + } + + function pushProvider(providerFiber) { + var context = providerFiber.type.context; + + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + + { + warning( + context._currentRenderer === null || + context._currentRenderer === rendererSigil, + "Detected multiple renderers concurrently rendering the " + + "same context provider. This is currently unsupported." + ); + context._currentRenderer = rendererSigil; + } + } + + function popProvider(providerFiber) { + var changedBits = changedBitsCursor.current; + var currentValue = valueCursor.current; + + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + + var context = providerFiber.type.context; + context._currentValue = currentValue; + context._changedBits = changedBits; + } + + return { + pushProvider: pushProvider, + popProvider: popProvider + }; +}; + +var ReactFiberStack = function() { + var valueStack = []; + + var fiberStack = void 0; + + { + fiberStack = []; + } + + var index = -1; + + function createCursor(defaultValue) { + return { + current: defaultValue + }; + } + + function isEmpty() { + return index === -1; + } + + 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 checkThatStackIsEmpty() { + { + if (index !== -1) { + warning( + false, + "Expected an empty stack. Something was not reset properly." + ); + } + } + } + + function resetStackAfterFatalErrorInDev() { + { + index = -1; + valueStack.length = 0; + fiberStack.length = 0; + } + } + + return { + createCursor: createCursor, + isEmpty: isEmpty, + pop: pop, + push: push, + checkThatStackIsEmpty: checkThatStackIsEmpty, + resetStackAfterFatalErrorInDev: resetStackAfterFatalErrorInDev + }; +}; + var invokeGuardedCallback$2 = ReactErrorUtils.invokeGuardedCallback; var hasCaughtError = ReactErrorUtils.hasCaughtError; var clearCaughtError = ReactErrorUtils.clearCaughtError; @@ -11779,16 +11869,23 @@ var warnAboutInvalidUpdates = void 0; } var ReactFiberScheduler = function(config) { - var hostContext = ReactFiberHostContext(config); + var stack = ReactFiberStack(); + var hostContext = ReactFiberHostContext(config, stack); + var legacyContext = ReactFiberLegacyContext(stack); + var newContext = ReactFiberNewContext(stack); var popHostContext = hostContext.popHostContext, popHostContainer = hostContext.popHostContainer; + var popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popLegacyContextProvider = legacyContext.popContextProvider; + var popProvider = newContext.popProvider; var hydrationContext = ReactFiberHydrationContext(config); - var resetHostContainer = hostContext.resetHostContainer; var _ReactFiberBeginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -11798,17 +11895,22 @@ var ReactFiberScheduler = function(config) { var _ReactFiberCompleteWo = ReactFiberCompleteWork( config, hostContext, + legacyContext, + newContext, hydrationContext ), completeWork = _ReactFiberCompleteWo.completeWork; var _ReactFiberUnwindWork = ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ), throwException = _ReactFiberUnwindWork.throwException, - unwindWork = _ReactFiberUnwindWork.unwindWork; + unwindWork = _ReactFiberUnwindWork.unwindWork, + unwindInterruptedWork = _ReactFiberUnwindWork.unwindInterruptedWork; var _ReactFiberCommitWork = ReactFiberCommitWork( config, @@ -11877,13 +11979,13 @@ var ReactFiberScheduler = function(config) { switch (failedUnitOfWork.tag) { case HostRoot: popHostContainer(failedUnitOfWork); - popTopLevelContextObject(failedUnitOfWork); + popTopLevelLegacyContextObject(failedUnitOfWork); break; case HostComponent: popHostContext(failedUnitOfWork); break; case ClassComponent: - popContextProvider(failedUnitOfWork); + popLegacyContextProvider(failedUnitOfWork); break; case HostPortal: popHostContainer(failedUnitOfWork); @@ -11903,18 +12005,18 @@ var ReactFiberScheduler = function(config) { }; } - function resetContextStack() { - // Reset the stack - reset(); - // Reset the cursors - resetContext(); - resetHostContainer(); - - // TODO: Unify new context implementation with other stacks - resetProviderStack(); + function resetStack() { + if (nextUnitOfWork !== null) { + var interruptedWork = nextUnitOfWork["return"]; + while (interruptedWork !== null) { + unwindInterruptedWork(interruptedWork); + interruptedWork = interruptedWork["return"]; + } + } { ReactStrictModeWarnings.discardPendingWarnings(); + stack.checkThatStackIsEmpty(); } nextRoot = null; @@ -12438,7 +12540,7 @@ var ReactFiberScheduler = function(config) { nextUnitOfWork === null ) { // Reset the stack and start working from the root. - resetContextStack(); + resetStack(); nextRoot = root; nextRenderExpirationTime = expirationTime; nextUnitOfWork = createWorkInProgress( @@ -12491,6 +12593,9 @@ var ReactFiberScheduler = function(config) { // Yield back to main thread. if (didFatal) { // There was a fatal error. + { + stack.resetStackAfterFatalErrorInDev(); + } return null; } else if (nextUnitOfWork === null) { // We reached the root. @@ -12691,7 +12796,7 @@ var ReactFiberScheduler = function(config) { ) { // This is an interruption. (Used for performance tracking.) interruptedBy = fiber; - resetContextStack(); + resetStack(); } if (nextRoot !== root || !isWorking) { requestWork(root, expirationTime); @@ -13262,7 +13367,8 @@ var ReactFiberScheduler = function(config) { syncUpdates: syncUpdates, interactiveUpdates: interactiveUpdates, flushInteractiveUpdates: flushInteractiveUpdates, - computeUniqueAsyncExpiration: computeUniqueAsyncExpiration + computeUniqueAsyncExpiration: computeUniqueAsyncExpiration, + legacyContext: legacyContext }; }; @@ -13275,18 +13381,6 @@ var didWarnAboutNestedUpdates = void 0; // 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; @@ -13305,7 +13399,24 @@ var ReactFiberReconciler$1 = function(config) { deferredUpdates = _ReactFiberScheduler.deferredUpdates, syncUpdates = _ReactFiberScheduler.syncUpdates, interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, - flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates; + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates, + legacyContext = _ReactFiberScheduler.legacyContext; + + var findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; + + function getContextForSubtree(parentComponent) { + if (!parentComponent) { + return emptyObject; + } + + var fiber = get(parentComponent); + var parentContext = findCurrentUnmaskedContext(fiber); + return isContextProvider(fiber) + ? processChildContext(fiber, parentContext) + : parentContext; + } function scheduleRootUpdate( current, diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index 258608b7f..f11aa6c82 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -1822,141 +1822,6 @@ function findCurrentHostFiberWithNoPortals(parent) { } return null; } -var valueStack = [], - index = -1; -function pop(cursor) { - 0 > index || - ((cursor.current = valueStack[index]), (valueStack[index] = null), index--); -} -function push(cursor, value) { - index++; - valueStack[index] = cursor.current; - cursor.current = value; -} -function getStackAddendumByWorkInProgressFiber(workInProgress) { - var info = ""; - do { - a: switch (workInProgress.tag) { - case 0: - case 1: - case 2: - case 5: - var owner = workInProgress._debugOwner, - source = workInProgress._debugSource; - var JSCompiler_inline_result = getComponentName(workInProgress); - var ownerName = null; - owner && (ownerName = getComponentName(owner)); - owner = source; - JSCompiler_inline_result = - "\n in " + - (JSCompiler_inline_result || "Unknown") + - (owner - ? " (at " + - owner.fileName.replace(/^.*[\\\/]/, "") + - ":" + - owner.lineNumber + - ")" - : ownerName ? " (created by " + ownerName + ")" : ""); - break a; - default: - JSCompiler_inline_result = ""; - } - info += JSCompiler_inline_result; - workInProgress = workInProgress["return"]; - } while (workInProgress); - return info; -} -var _require = require("ReactFeatureFlags"), - enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch, - debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects, - debugRenderPhaseSideEffectsForStrictMode = - _require.debugRenderPhaseSideEffectsForStrictMode; -new Set(); -var contextStackCursor = { current: emptyObject }, - didPerformWorkStackCursor = { current: !1 }, - previousContext = emptyObject; -function getUnmaskedContext(workInProgress) { - return isContextProvider(workInProgress) - ? previousContext - : contextStackCursor.current; -} -function getMaskedContext(workInProgress, unmaskedContext) { - var contextTypes = workInProgress.type.contextTypes; - if (!contextTypes) return emptyObject; - var instance = workInProgress.stateNode; - if ( - instance && - instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext - ) - return instance.__reactInternalMemoizedMaskedChildContext; - var context = {}, - key; - for (key in contextTypes) context[key] = unmaskedContext[key]; - instance && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); - return context; -} -function isContextProvider(fiber) { - return 2 === fiber.tag && null != fiber.type.childContextTypes; -} -function popContextProvider(fiber) { - isContextProvider(fiber) && - (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); -} -function pushTopLevelContextObject(fiber, context, didChange) { - invariant( - null == contextStackCursor.cursor, - "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." - ); - push(contextStackCursor, context, fiber); - push(didPerformWorkStackCursor, didChange, fiber); -} -function processChildContext(fiber, parentContext) { - var instance = fiber.stateNode, - childContextTypes = fiber.type.childContextTypes; - if ("function" !== typeof instance.getChildContext) return parentContext; - instance = instance.getChildContext(); - for (var contextKey in instance) - invariant( - contextKey in childContextTypes, - '%s.getChildContext(): key "%s" is not defined in childContextTypes.', - getComponentName(fiber) || "Unknown", - contextKey - ); - return Object.assign({}, parentContext, instance); -} -function pushContextProvider(workInProgress) { - if (!isContextProvider(workInProgress)) return !1; - var instance = workInProgress.stateNode; - instance = - (instance && instance.__reactInternalMemoizedMergedChildContext) || - emptyObject; - previousContext = contextStackCursor.current; - push(contextStackCursor, instance, workInProgress); - push( - didPerformWorkStackCursor, - didPerformWorkStackCursor.current, - workInProgress - ); - return !0; -} -function invalidateContextProvider(workInProgress, didChange) { - var instance = workInProgress.stateNode; - invariant( - instance, - "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." - ); - if (didChange) { - var mergedContext = processChildContext(workInProgress, previousContext); - instance.__reactInternalMemoizedMergedChildContext = mergedContext; - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); - push(contextStackCursor, mergedContext, workInProgress); - } else pop(didPerformWorkStackCursor, workInProgress); - push(didPerformWorkStackCursor, didChange, workInProgress); -} function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; @@ -2123,6 +1988,45 @@ function onCommitRoot(root) { function onCommitUnmount(fiber) { "function" === typeof onCommitFiberUnmount && onCommitFiberUnmount(fiber); } +function getStackAddendumByWorkInProgressFiber(workInProgress) { + var info = ""; + do { + a: switch (workInProgress.tag) { + case 0: + case 1: + case 2: + case 5: + var owner = workInProgress._debugOwner, + source = workInProgress._debugSource; + var JSCompiler_inline_result = getComponentName(workInProgress); + var ownerName = null; + owner && (ownerName = getComponentName(owner)); + owner = source; + JSCompiler_inline_result = + "\n in " + + (JSCompiler_inline_result || "Unknown") + + (owner + ? " (at " + + owner.fileName.replace(/^.*[\\\/]/, "") + + ":" + + owner.lineNumber + + ")" + : ownerName ? " (created by " + ownerName + ")" : ""); + break a; + default: + JSCompiler_inline_result = ""; + } + info += JSCompiler_inline_result; + workInProgress = workInProgress["return"]; + } while (workInProgress); + return info; +} +var _require = require("ReactFeatureFlags"), + enableGetDerivedStateFromCatch = _require.enableGetDerivedStateFromCatch, + debugRenderPhaseSideEffects = _require.debugRenderPhaseSideEffects, + debugRenderPhaseSideEffectsForStrictMode = + _require.debugRenderPhaseSideEffectsForStrictMode; +new Set(); function createUpdateQueue(baseState) { return { baseState: baseState, @@ -2294,6 +2198,7 @@ function callGetDerivedStateFromCatch(ctor, capturedValues) { return resultState; } function ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, memoizeProps, @@ -2360,62 +2265,66 @@ function ReactFiberClassComponent( ) ); } - var updater = { - isMounted: isMounted, - enqueueSetState: function(instance, partialState, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: partialState, - callback: callback, - isReplace: !1, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueReplaceState: function(instance, state, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: state, - callback: callback, - isReplace: !0, - isForced: !1, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - }, - enqueueForceUpdate: function(instance, callback) { - instance = instance._reactInternalFiber; - callback = void 0 === callback ? null : callback; - var expirationTime = computeExpirationForFiber(instance); - insertUpdateIntoFiber(instance, { - expirationTime: expirationTime, - partialState: null, - callback: callback, - isReplace: !1, - isForced: !0, - capturedValue: null, - next: null - }); - scheduleWork(instance, expirationTime); - } - }; + var cacheContext = legacyContext.cacheContext, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + isContextConsumer = legacyContext.isContextConsumer, + hasContextChanged = legacyContext.hasContextChanged, + updater = { + isMounted: isMounted, + enqueueSetState: function(instance, partialState, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: partialState, + callback: callback, + isReplace: !1, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueReplaceState: function(instance, state, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: state, + callback: callback, + isReplace: !0, + isForced: !1, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + }, + enqueueForceUpdate: function(instance, callback) { + instance = instance._reactInternalFiber; + callback = void 0 === callback ? null : callback; + var expirationTime = computeExpirationForFiber(instance); + insertUpdateIntoFiber(instance, { + expirationTime: expirationTime, + partialState: null, + callback: callback, + isReplace: !1, + isForced: !0, + capturedValue: null, + next: null + }); + scheduleWork(instance, expirationTime); + } + }; return { adoptClassInstance: adoptClassInstance, callGetDerivedStateFromProps: callGetDerivedStateFromProps, constructClassInstance: function(workInProgress, props) { var ctor = workInProgress.type, unmaskedContext = getUnmaskedContext(workInProgress), - needsContext = - 2 === workInProgress.tag && null != workInProgress.type.contextTypes, + needsContext = isContextConsumer(workInProgress), context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; @@ -2436,10 +2345,7 @@ function ReactFiberClassComponent( workInProgress.memoizedState, props )); - needsContext && - ((workInProgress = workInProgress.stateNode), - (workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext), - (workInProgress.__reactInternalMemoizedMaskedChildContext = context)); + needsContext && cacheContext(workInProgress, unmaskedContext, context); return ctor; }, mountClassInstance: function(workInProgress, renderExpirationTime) { @@ -2539,7 +2445,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldState !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -2643,7 +2549,7 @@ function ReactFiberClassComponent( !( oldProps !== newProps || oldContext !== renderExpirationTime || - didPerformWorkStackCursor.current || + hasContextChanged() || (null !== workInProgress.updateQueue && workInProgress.updateQueue.hasForceUpdate) ) @@ -3366,34 +3272,12 @@ function ChildReconciler(shouldTrackSideEffects) { }; } var reconcileChildFibers = ChildReconciler(!0), - mountChildFibers = ChildReconciler(!1), - changedBitsStack = [], - currentValueStack = [], - stack = [], - index$1 = -1; -function pushProvider(providerFiber) { - var context = providerFiber.type.context; - index$1 += 1; - changedBitsStack[index$1] = context._changedBits; - currentValueStack[index$1] = context._currentValue; - stack[index$1] = providerFiber; - context._currentValue = providerFiber.pendingProps.value; - context._changedBits = providerFiber.stateNode; -} -function popProvider(providerFiber) { - var changedBits = changedBitsStack[index$1], - currentValue = currentValueStack[index$1]; - changedBitsStack[index$1] = null; - currentValueStack[index$1] = null; - stack[index$1] = null; - --index$1; - providerFiber = providerFiber.type.context; - providerFiber._currentValue = currentValue; - providerFiber._changedBits = changedBits; -} + mountChildFibers = ChildReconciler(!1); function ReactFiberBeginWork( config, hostContext, + legacyContext, + newContext, hydrationContext, scheduleWork, computeExpirationForFiber @@ -3499,7 +3383,12 @@ function ReactFiberBeginWork( changedBits, renderExpirationTime ) { - for (var fiber = workInProgress.child; null !== fiber; ) { + var fiber = workInProgress.child; + for ( + null !== fiber && (fiber["return"] = workInProgress); + null !== fiber; + + ) { switch (fiber.tag) { case 12: var nextFiber = fiber.stateNode | 0; @@ -3558,7 +3447,7 @@ function ReactFiberBeginWork( var context = workInProgress.type.context, newProps = workInProgress.pendingProps, oldProps = workInProgress.memoizedProps; - if (!didPerformWorkStackCursor.current && oldProps === newProps) + if (!hasLegacyContextChanged() && oldProps === newProps) return ( (workInProgress.stateNode = 0), pushProvider(workInProgress), @@ -3645,11 +3534,19 @@ function ReactFiberBeginWork( shouldDeprioritizeSubtree = config.shouldDeprioritizeSubtree, pushHostContext = hostContext.pushHostContext, pushHostContainer = hostContext.pushHostContainer, + pushProvider = newContext.pushProvider, + getMaskedContext = legacyContext.getMaskedContext, + getUnmaskedContext = legacyContext.getUnmaskedContext, + hasLegacyContextChanged = legacyContext.hasContextChanged, + pushLegacyContextProvider = legacyContext.pushContextProvider, + pushTopLevelContextObject = legacyContext.pushTopLevelContextObject, + invalidateContextProvider = legacyContext.invalidateContextProvider, enterHydrationState = hydrationContext.enterHydrationState, resetHydrationState = hydrationContext.resetHydrationState, tryToClaimNextHydratableInstance = hydrationContext.tryToClaimNextHydratableInstance; config = ReactFiberClassComponent( + legacyContext, scheduleWork, computeExpirationForFiber, function(workInProgress, nextProps) { @@ -3676,7 +3573,7 @@ function ReactFiberBeginWork( pushHostRootContext(workInProgress); break; case 2: - pushContextProvider(workInProgress); + pushLegacyContextProvider(workInProgress); break; case 4: pushHostContainer( @@ -3722,7 +3619,7 @@ function ReactFiberBeginWork( workInProgress.memoizedState, props ))), - (props = pushContextProvider(workInProgress)), + (props = pushLegacyContextProvider(workInProgress)), adoptClassInstance(workInProgress, fn), mountClassInstance(workInProgress, renderExpirationTime), (current = finishClassComponent( @@ -3742,7 +3639,7 @@ function ReactFiberBeginWork( return ( (props = workInProgress.type), (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? ((fn = getUnmaskedContext(workInProgress)), (fn = getMaskedContext(workInProgress, fn)), @@ -3758,7 +3655,7 @@ function ReactFiberBeginWork( current ); case 2: - props = pushContextProvider(workInProgress); + props = pushLegacyContextProvider(workInProgress); null === current ? null === workInProgress.stateNode ? (constructClassInstance( @@ -3840,7 +3737,7 @@ function ReactFiberBeginWork( updateQueue = workInProgress.memoizedProps; fn = workInProgress.pendingProps; unmaskedContext = null !== current ? current.memoizedProps : null; - if (!didPerformWorkStackCursor.current && updateQueue === fn) { + if (!hasLegacyContextChanged() && updateQueue === fn) { if ( (updateQueue = workInProgress.mode & 1 && @@ -3882,7 +3779,7 @@ function ReactFiberBeginWork( case 7: return ( (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== props || (props = workInProgress.memoizedProps), (fn = props.children), @@ -3912,8 +3809,7 @@ function ReactFiberBeginWork( workInProgress.stateNode.containerInfo ), (props = workInProgress.pendingProps), - didPerformWorkStackCursor.current || - workInProgress.memoizedProps !== props + hasLegacyContextChanged() || workInProgress.memoizedProps !== props ? (null === current ? (workInProgress.child = reconcileChildFibers( workInProgress, @@ -3944,7 +3840,7 @@ function ReactFiberBeginWork( case 10: return ( (renderExpirationTime = workInProgress.pendingProps), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || workInProgress.memoizedProps !== renderExpirationTime ? (reconcileChildren( current, @@ -3962,7 +3858,7 @@ function ReactFiberBeginWork( case 11: return ( (renderExpirationTime = workInProgress.pendingProps.children), - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || (null !== renderExpirationTime && workInProgress.memoizedProps !== renderExpirationTime) ? (reconcileChildren( @@ -3992,7 +3888,7 @@ function ReactFiberBeginWork( props = fn._currentValue; var changedBits = fn._changedBits; if ( - didPerformWorkStackCursor.current || + hasLegacyContextChanged() || 0 !== changedBits || updateQueue !== unmaskedContext ) { @@ -4032,7 +3928,13 @@ function ReactFiberBeginWork( } }; } -function ReactFiberCompleteWork(config, hostContext, hydrationContext) { +function ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + newContext, + hydrationContext +) { function markUpdate(workInProgress) { workInProgress.effectTag |= 4; } @@ -4046,6 +3948,9 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { popHostContext = hostContext.popHostContext, getHostContext = hostContext.getHostContext, popHostContainer = hostContext.popHostContainer, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider, prepareToHydrateHostInstance = hydrationContext.prepareToHydrateHostInstance, prepareToHydrateHostTextInstance = @@ -4074,7 +3979,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { return null; case 2: return ( - popContextProvider(workInProgress), + popLegacyContextProvider(workInProgress), (current = workInProgress.stateNode), (newProps = workInProgress.updateQueue), null !== newProps && @@ -4087,8 +3992,7 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { ); case 3: popHostContainer(workInProgress); - pop(didPerformWorkStackCursor, workInProgress); - pop(contextStackCursor, workInProgress); + popTopLevelLegacyContextObject(workInProgress); newProps = workInProgress.stateNode; newProps.pendingContext && ((newProps.context = newProps.pendingContext), @@ -4304,11 +4208,16 @@ function ReactFiberCompleteWork(config, hostContext, hydrationContext) { } function ReactFiberUnwindWork( hostContext, + legacyContext, + newContext, scheduleWork, isAlreadyFailedLegacyErrorBoundary ) { var popHostContainer = hostContext.popHostContainer, - popHostContext = hostContext.popHostContext; + popHostContext = hostContext.popHostContext, + popLegacyContextProvider = legacyContext.popContextProvider, + popTopLevelLegacyContextObject = legacyContext.popTopLevelContextObject, + popProvider = newContext.popProvider; return { throwException: function(returnFiber, sourceFiber, rawValue) { sourceFiber.effectTag |= 512; @@ -4352,7 +4261,7 @@ function ReactFiberUnwindWork( unwindWork: function(workInProgress) { switch (workInProgress.tag) { case 2: - popContextProvider(workInProgress); + popLegacyContextProvider(workInProgress); var effectTag = workInProgress.effectTag; return effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4361,8 +4270,7 @@ function ReactFiberUnwindWork( case 3: return ( popHostContainer(workInProgress), - pop(didPerformWorkStackCursor, workInProgress), - pop(contextStackCursor, workInProgress), + popTopLevelLegacyContextObject(workInProgress), (effectTag = workInProgress.effectTag), effectTag & 1024 ? ((workInProgress.effectTag = (effectTag & -1025) | 64), @@ -4378,6 +4286,25 @@ function ReactFiberUnwindWork( default: return null; } + }, + unwindInterruptedWork: function(interruptedWork) { + switch (interruptedWork.tag) { + case 2: + popLegacyContextProvider(interruptedWork); + break; + case 3: + popHostContainer(interruptedWork); + popTopLevelLegacyContextObject(interruptedWork); + break; + case 5: + popHostContext(interruptedWork); + break; + case 4: + popHostContainer(interruptedWork); + break; + case 13: + popProvider(interruptedWork); + } } }; } @@ -4819,7 +4746,7 @@ function ReactFiberCommitWork( }; } var NO_CONTEXT = {}; -function ReactFiberHostContext(config) { +function ReactFiberHostContext(config, stack) { function requiredContext(c) { invariant( c !== NO_CONTEXT, @@ -4828,10 +4755,13 @@ function ReactFiberHostContext(config) { return c; } var getChildHostContext = config.getChildHostContext, - getRootHostContext = config.getRootHostContext, - contextStackCursor = { current: NO_CONTEXT }, - contextFiberStackCursor = { current: NO_CONTEXT }, - rootInstanceStackCursor = { current: NO_CONTEXT }; + getRootHostContext = config.getRootHostContext; + config = stack.createCursor; + var push = stack.push, + pop = stack.pop, + contextStackCursor = config(NO_CONTEXT), + contextFiberStackCursor = config(NO_CONTEXT), + rootInstanceStackCursor = config(NO_CONTEXT); return { getHostContext: function() { return requiredContext(contextStackCursor.current); @@ -4861,10 +4791,6 @@ function ReactFiberHostContext(config) { context !== rootInstance && (push(contextFiberStackCursor, fiber, fiber), push(contextStackCursor, rootInstance, fiber)); - }, - resetHostContainer: function() { - contextStackCursor.current = NO_CONTEXT; - rootInstanceStackCursor.current = NO_CONTEXT; } }; } @@ -5024,22 +4950,198 @@ function ReactFiberHydrationContext(config) { } }; } -function ReactFiberScheduler(config) { - function resetContextStack() { - for (; -1 < index; ) (valueStack[index] = null), index--; +function ReactFiberLegacyContext(stack) { + function cacheContext(workInProgress, unmaskedContext, maskedContext) { + workInProgress = workInProgress.stateNode; + workInProgress.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; + workInProgress.__reactInternalMemoizedMaskedChildContext = maskedContext; + } + function isContextProvider(fiber) { + return 2 === fiber.tag && null != fiber.type.childContextTypes; + } + function processChildContext(fiber, parentContext) { + var instance = fiber.stateNode, + childContextTypes = fiber.type.childContextTypes; + if ("function" !== typeof instance.getChildContext) return parentContext; + instance = instance.getChildContext(); + for (var contextKey in instance) + invariant( + contextKey in childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + getComponentName(fiber) || "Unknown", + contextKey + ); + return Object.assign({}, parentContext, instance); + } + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + contextStackCursor = createCursor(emptyObject), + didPerformWorkStackCursor = createCursor(!1), previousContext = emptyObject; - contextStackCursor.current = emptyObject; - didPerformWorkStackCursor.current = !1; - resetHostContainer(); - for (var i = index$1; -1 < i; i--) { - var context = stack[i].type.context; - context._currentValue = context._defaultValue; - context._changedBits = 0; - changedBitsStack[i] = null; - currentValueStack[i] = null; - stack[i] = null; + return { + getUnmaskedContext: function(workInProgress) { + return isContextProvider(workInProgress) + ? previousContext + : contextStackCursor.current; + }, + cacheContext: cacheContext, + getMaskedContext: function(workInProgress, unmaskedContext) { + var contextTypes = workInProgress.type.contextTypes; + if (!contextTypes) return emptyObject; + var instance = workInProgress.stateNode; + if ( + instance && + instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext + ) + return instance.__reactInternalMemoizedMaskedChildContext; + var context = {}, + key; + for (key in contextTypes) context[key] = unmaskedContext[key]; + instance && cacheContext(workInProgress, unmaskedContext, context); + return context; + }, + hasContextChanged: function() { + return didPerformWorkStackCursor.current; + }, + isContextConsumer: function(fiber) { + return 2 === fiber.tag && null != fiber.type.contextTypes; + }, + isContextProvider: isContextProvider, + popContextProvider: function(fiber) { + isContextProvider(fiber) && + (pop(didPerformWorkStackCursor, fiber), pop(contextStackCursor, fiber)); + }, + popTopLevelContextObject: function(fiber) { + pop(didPerformWorkStackCursor, fiber); + pop(contextStackCursor, fiber); + }, + pushTopLevelContextObject: function(fiber, context, didChange) { + invariant( + null == contextStackCursor.cursor, + "Unexpected context found on stack. This error is likely caused by a bug in React. Please file an issue." + ); + push(contextStackCursor, context, fiber); + push(didPerformWorkStackCursor, didChange, fiber); + }, + processChildContext: processChildContext, + pushContextProvider: function(workInProgress) { + if (!isContextProvider(workInProgress)) return !1; + var instance = workInProgress.stateNode; + instance = + (instance && instance.__reactInternalMemoizedMergedChildContext) || + emptyObject; + previousContext = contextStackCursor.current; + push(contextStackCursor, instance, workInProgress); + push( + didPerformWorkStackCursor, + didPerformWorkStackCursor.current, + workInProgress + ); + return !0; + }, + invalidateContextProvider: function(workInProgress, didChange) { + var instance = workInProgress.stateNode; + invariant( + instance, + "Expected to have an instance by this point. This error is likely caused by a bug in React. Please file an issue." + ); + if (didChange) { + var mergedContext = processChildContext( + workInProgress, + previousContext + ); + instance.__reactInternalMemoizedMergedChildContext = mergedContext; + pop(didPerformWorkStackCursor, workInProgress); + pop(contextStackCursor, workInProgress); + push(contextStackCursor, mergedContext, workInProgress); + } else pop(didPerformWorkStackCursor, workInProgress); + push(didPerformWorkStackCursor, didChange, workInProgress); + }, + findCurrentUnmaskedContext: function(fiber) { + for ( + invariant( + 2 === isFiberMountedImpl(fiber) && 2 === fiber.tag, + "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." + ); + 3 !== fiber.tag; + + ) { + if (isContextProvider(fiber)) + return fiber.stateNode.__reactInternalMemoizedMergedChildContext; + fiber = fiber["return"]; + invariant( + fiber, + "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." + ); + } + return fiber.stateNode.context; } - index$1 = -1; + }; +} +function ReactFiberNewContext(stack) { + var createCursor = stack.createCursor, + push = stack.push, + pop = stack.pop, + providerCursor = createCursor(null), + valueCursor = createCursor(null), + changedBitsCursor = createCursor(0); + return { + pushProvider: function(providerFiber) { + var context = providerFiber.type.context; + push(changedBitsCursor, context._changedBits, providerFiber); + push(valueCursor, context._currentValue, providerFiber); + push(providerCursor, providerFiber, providerFiber); + context._currentValue = providerFiber.pendingProps.value; + context._changedBits = providerFiber.stateNode; + }, + popProvider: function(providerFiber) { + var changedBits = changedBitsCursor.current, + currentValue = valueCursor.current; + pop(providerCursor, providerFiber); + pop(valueCursor, providerFiber); + pop(changedBitsCursor, providerFiber); + providerFiber = providerFiber.type.context; + providerFiber._currentValue = currentValue; + providerFiber._changedBits = changedBits; + } + }; +} +function ReactFiberStack() { + var valueStack = [], + index = -1; + return { + createCursor: function(defaultValue) { + return { current: defaultValue }; + }, + isEmpty: function() { + return -1 === index; + }, + pop: function(cursor) { + 0 > index || + ((cursor.current = valueStack[index]), + (valueStack[index] = null), + index--); + }, + push: function(cursor, value) { + index++; + valueStack[index] = cursor.current; + cursor.current = value; + }, + checkThatStackIsEmpty: function() {}, + resetStackAfterFatalErrorInDev: function() {} + }; +} +function ReactFiberScheduler(config) { + function resetStack() { + if (null !== nextUnitOfWork) + for ( + var interruptedWork = nextUnitOfWork["return"]; + null !== interruptedWork; + + ) + unwindInterruptedWork(interruptedWork), + (interruptedWork = interruptedWork["return"]); nextRoot = null; nextRenderExpirationTime = 0; nextUnitOfWork = null; @@ -5145,7 +5247,7 @@ function ReactFiberScheduler(config) { root !== nextRoot || null === nextUnitOfWork ) - resetContextStack(), + resetStack(), (nextRoot = root), (nextRenderExpirationTime = expirationTime), (nextUnitOfWork = createWorkInProgress( @@ -5275,7 +5377,7 @@ function ReactFiberScheduler(config) { !isWorking && 0 !== nextRenderExpirationTime && expirationTime < nextRenderExpirationTime && - resetContextStack(); + resetStack(); (nextRoot === root && isWorking) || requestWork(root, expirationTime); nestedUpdateCount > NESTED_UPDATE_LIMIT && @@ -5619,25 +5721,37 @@ function ReactFiberScheduler(config) { nextFlushedRoot.remainingExpirationTime = 0; hasUnhandledError || ((hasUnhandledError = !0), (unhandledError = error)); } - var hostContext = ReactFiberHostContext(config), - hydrationContext = ReactFiberHydrationContext(config), - resetHostContainer = hostContext.resetHostContainer, + var stack = ReactFiberStack(), + hostContext = ReactFiberHostContext(config, stack), + legacyContext = ReactFiberLegacyContext(stack); + stack = ReactFiberNewContext(stack); + var hydrationContext = ReactFiberHydrationContext(config), beginWork = ReactFiberBeginWork( config, hostContext, + legacyContext, + stack, hydrationContext, scheduleWork, computeExpirationForFiber ).beginWork, - completeWork = ReactFiberCompleteWork(config, hostContext, hydrationContext) - .completeWork; + completeWork = ReactFiberCompleteWork( + config, + hostContext, + legacyContext, + stack, + hydrationContext + ).completeWork; hostContext = ReactFiberUnwindWork( hostContext, + legacyContext, + stack, scheduleWork, isAlreadyFailedLegacyErrorBoundary ); var throwException = hostContext.throwException, - unwindWork = hostContext.unwindWork; + unwindWork = hostContext.unwindWork, + unwindInterruptedWork = hostContext.unwindInterruptedWork; hostContext = ReactFiberCommitWork( config, onCommitPhaseError, @@ -5796,7 +5910,8 @@ function ReactFiberScheduler(config) { result <= lastUniqueAsyncExpiration && (result = lastUniqueAsyncExpiration + 1); return (lastUniqueAsyncExpiration = result); - } + }, + legacyContext: legacyContext }; } function ReactFiberReconciler$1(config) { @@ -5811,27 +5926,7 @@ function ReactFiberReconciler$1(config) { currentTime = container.current; if (parentComponent) { parentComponent = parentComponent._reactInternalFiber; - var parentContext; - b: { - invariant( - 2 === isFiberMountedImpl(parentComponent) && - 2 === parentComponent.tag, - "Expected subtree parent to be a mounted class component. This error is likely caused by a bug in React. Please file an issue." - ); - for (parentContext = parentComponent; 3 !== parentContext.tag; ) { - if (isContextProvider(parentContext)) { - parentContext = - parentContext.stateNode.__reactInternalMemoizedMergedChildContext; - break b; - } - parentContext = parentContext["return"]; - invariant( - parentContext, - "Found unexpected detached subtree parent. This error is likely caused by a bug in React. Please file an issue." - ); - } - parentContext = parentContext.stateNode.context; - } + var parentContext = findCurrentUnmaskedContext(parentComponent); parentComponent = isContextProvider(parentComponent) ? processChildContext(parentComponent, parentContext) : parentContext; @@ -5860,7 +5955,11 @@ function ReactFiberReconciler$1(config) { config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, computeExpirationForFiber = config.computeExpirationForFiber, - scheduleWork = config.scheduleWork; + scheduleWork = config.scheduleWork, + legacyContext = config.legacyContext, + findCurrentUnmaskedContext = legacyContext.findCurrentUnmaskedContext, + isContextProvider = legacyContext.isContextProvider, + processChildContext = legacyContext.processChildContext; return { createContainer: function(containerInfo, isAsync, hydrate) { isAsync = new FiberNode(3, null, null, isAsync ? 3 : 0); diff --git a/Libraries/Renderer/shims/ReactFabric.js b/Libraries/Renderer/shims/ReactFabric.js index 4a396c224..6ab336bf1 100644 --- a/Libraries/Renderer/shims/ReactFabric.js +++ b/Libraries/Renderer/shims/ReactFabric.js @@ -9,6 +9,8 @@ */ 'use strict'; +const BatchedBridge = require('BatchedBridge'); + // TODO @sema: Adjust types import type {ReactNativeType} from 'ReactNativeTypes'; @@ -20,4 +22,7 @@ if (__DEV__) { ReactFabric = require('ReactFabric-prod'); } +BatchedBridge.registerCallableModule('ReactFabric', ReactFabric); + module.exports = (ReactFabric: ReactNativeType); +