diff --git a/Libraries/Renderer/REVISION b/Libraries/Renderer/REVISION index 7a75297ce..69753c2a9 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -a7b9f98e7abab7305978b4b36881c8267a450097 \ No newline at end of file +4eed18dd72cb811de11bd34b8ff86e4d193c7d4e \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index 08e0c16af..f504078fa 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -2550,6 +2550,10 @@ function restoreStateOfTarget(target) { ); } +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} + function restoreStateIfNeeded() { if (!restoreTarget) { return; @@ -2574,39 +2578,49 @@ function restoreStateIfNeeded() { // scheduled work and instead do synchronous work. // Defaults -var fiberBatchedUpdates = function(fn, bookkeeping) { +var _batchedUpdates = function(fn, bookkeeping) { return fn(bookkeeping); }; +var _interactiveUpdates = function(fn, a, b) { + return fn(a, b); +}; +var _flushInteractiveUpdates = function() {}; -var isNestingBatched = false; +var isBatching = false; function batchedUpdates(fn, bookkeeping) { - if (isNestingBatched) { + if (isBatching) { // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. Therefore, we add the target to - // a queue of work. - return fiberBatchedUpdates(fn, bookkeeping); + // fully completes before restoring state. + return fn(bookkeeping); } - isNestingBatched = true; + isBatching = true; try { - return fiberBatchedUpdates(fn, bookkeeping); + return _batchedUpdates(fn, bookkeeping); } finally { // Here we wait until all updates have propagated, which is important // when using controlled components within layers: // https://github.com/facebook/react/issues/1698 // Then we restore state of any controlled component. - isNestingBatched = false; - restoreStateIfNeeded(); + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdates(); + restoreStateIfNeeded(); + } } } -var ReactGenericBatchingInjection = { - injectFiberBatchedUpdates: function(_batchedUpdates) { - fiberBatchedUpdates = _batchedUpdates; +var injection$2 = { + injectRenderer: function(renderer) { + _batchedUpdates = renderer.batchedUpdates; + _interactiveUpdates = renderer.interactiveUpdates; + _flushInteractiveUpdates = renderer.flushInteractiveUpdates; } }; -var injection$2 = ReactGenericBatchingInjection; - /** * Keeps track of allocating and associating native "tags" which are numeric, * unique view IDs. All the native tags are negative numbers, to avoid @@ -2868,6 +2882,9 @@ var REACT_STRICT_MODE_TYPE = hasSymbol : 0xeacc; var REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; +var REACT_ASYNC_MODE_TYPE = hasSymbol + ? Symbol["for"]("react.async_mode") + : 0xeacf; var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; var FAUX_ITERATOR_SYMBOL = "@@iterator"; @@ -4692,7 +4709,6 @@ var ReactDebugCurrentFiber = { getCurrentFiberStackAddendum: getCurrentFiberStackAddendum }; -var enableAsyncSubtreeAPI = true; // Exports ReactDOM.createRoot var enableUserTimingAPI = true; @@ -4703,9 +4719,6 @@ var enableMutatingReconciler = true; var enableNoopReconciler = false; // Experimental persistent mode (Fabric): var enablePersistentReconciler = false; -// Support for new context API -var enableNewContextAPI = false; - // Helps identify side effects in begin-phase lifecycle hooks and setState reducers: var debugRenderPhaseSideEffects = false; @@ -5444,7 +5457,7 @@ function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { } var NoContext = 0; -var AsyncUpdates = 1; +var AsyncMode = 1; var StrictMode = 2; var hasBadMapPolyfill = void 0; @@ -5475,7 +5488,7 @@ var debugCounter = void 0; debugCounter = 1; } -function FiberNode(tag, pendingProps, key, internalContextTag) { +function FiberNode(tag, pendingProps, key, mode) { // Instance this.tag = tag; this.key = key; @@ -5495,7 +5508,7 @@ function FiberNode(tag, pendingProps, key, internalContextTag) { this.updateQueue = null; this.memoizedState = null; - this.internalContextTag = internalContextTag; + this.mode = mode; // Effects this.effectTag = NoEffect; @@ -5532,9 +5545,9 @@ function FiberNode(tag, pendingProps, key, internalContextTag) { // is faster. // 5) It should be easy to port this to a C struct and keep a C implementation // compatible. -var createFiber = function(tag, pendingProps, key, internalContextTag) { +var createFiber = function(tag, pendingProps, key, mode) { // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, pendingProps, key, internalContextTag); + return new FiberNode(tag, pendingProps, key, mode); }; function shouldConstruct(Component) { @@ -5554,7 +5567,7 @@ function createWorkInProgress(current, pendingProps, expirationTime) { current.tag, pendingProps, current.key, - current.internalContextTag + current.mode ); workInProgress.type = current.type; workInProgress.stateNode = current.stateNode; @@ -5597,11 +5610,11 @@ function createWorkInProgress(current, pendingProps, expirationTime) { } function createHostRootFiber(isAsync) { - var internalContextTag = isAsync ? AsyncUpdates | StrictMode : NoContext; - return createFiber(HostRoot, null, null, internalContextTag); + var mode = isAsync ? AsyncMode | StrictMode : NoContext; + return createFiber(HostRoot, null, null, mode); } -function createFiberFromElement(element, internalContextTag, expirationTime) { +function createFiberFromElement(element, mode, expirationTime) { var owner = null; { owner = element._owner; @@ -5622,13 +5635,17 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment( pendingProps.children, - internalContextTag, + mode, expirationTime, key ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = Mode; + mode |= AsyncMode | StrictMode; + break; case REACT_STRICT_MODE_TYPE: fiberTag = Mode; - internalContextTag |= StrictMode; + mode |= StrictMode; break; case REACT_CALL_TYPE: fiberTag = CallComponent; @@ -5672,7 +5689,7 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { } } - fiber = createFiber(fiberTag, pendingProps, key, internalContextTag); + fiber = createFiber(fiberTag, pendingProps, key, mode); fiber.type = type; fiber.expirationTime = expirationTime; @@ -5713,19 +5730,14 @@ function throwOnInvalidElementType(type, owner) { ); } -function createFiberFromFragment( - elements, - internalContextTag, - expirationTime, - key -) { - var fiber = createFiber(Fragment, elements, key, internalContextTag); +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); fiber.expirationTime = expirationTime; return fiber; } -function createFiberFromText(content, internalContextTag, expirationTime) { - var fiber = createFiber(HostText, content, null, internalContextTag); +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); fiber.expirationTime = expirationTime; return fiber; } @@ -5736,14 +5748,9 @@ function createFiberFromHostInstanceForDeletion() { return fiber; } -function createFiberFromPortal(portal, internalContextTag, expirationTime) { +function createFiberFromPortal(portal, mode, expirationTime) { var pendingProps = portal.children !== null ? portal.children : []; - var fiber = createFiber( - HostPortal, - pendingProps, - portal.key, - internalContextTag - ); + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); fiber.expirationTime = expirationTime; fiber.stateNode = { containerInfo: portal.containerInfo, @@ -5933,7 +5940,7 @@ var ReactStrictModeWarnings = { var maybeStrictRoot = null; while (fiber !== null) { - if (fiber.internalContextTag & StrictMode) { + if (fiber.mode & StrictMode) { maybeStrictRoot = fiber; } @@ -6334,7 +6341,7 @@ function processUpdateQueue( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { getStateFromUpdate(update, instance, state, props); } @@ -6768,7 +6775,7 @@ var ReactFiberClassComponent = function( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { new ctor(props, context); // eslint-disable-line no-new } @@ -6833,7 +6840,8 @@ var ReactFiberClassComponent = function( if (typeof instance.componentWillMount === "function") { instance.componentWillMount(); - } else { + } + if (typeof instance.UNSAFE_componentWillMount === "function") { instance.UNSAFE_componentWillMount(); } @@ -6860,15 +6868,14 @@ var ReactFiberClassComponent = function( newContext ) { var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); if (typeof instance.componentWillReceiveProps === "function") { - startPhaseTimer(workInProgress, "componentWillReceiveProps"); instance.componentWillReceiveProps(newProps, newContext); - stopPhaseTimer(); - } else { - startPhaseTimer(workInProgress, "componentWillReceiveProps"); - instance.UNSAFE_componentWillReceiveProps(newProps, newContext); - stopPhaseTimer(); } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, newContext); + } + stopPhaseTimer(); if (instance.state !== oldState) { { @@ -6917,7 +6924,7 @@ var ReactFiberClassComponent = function( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { // Invoke method an extra time to help detect side-effects. type.getDerivedStateFromProps.call( @@ -6969,19 +6976,8 @@ var ReactFiberClassComponent = function( instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); - if (workInProgress.type != null && workInProgress.type.prototype != null) { - var prototype = workInProgress.type.prototype; - - if (enableAsyncSubtreeAPI) { - if (prototype.unstable_isAsyncReactComponent === true) { - workInProgress.internalContextTag |= AsyncUpdates; - workInProgress.internalContextTag |= StrictMode; - } - } - } - { - if (workInProgress.internalContextTag & StrictMode) { + if (workInProgress.mode & StrictMode) { ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( workInProgress, instance @@ -7235,15 +7231,14 @@ var ReactFiberClassComponent = function( typeof instance.componentWillUpdate === "function") && typeof workInProgress.type.getDerivedStateFromProps !== "function" ) { + startPhaseTimer(workInProgress, "componentWillUpdate"); if (typeof instance.componentWillUpdate === "function") { - startPhaseTimer(workInProgress, "componentWillUpdate"); instance.componentWillUpdate(newProps, newState, newContext); - stopPhaseTimer(); - } else { - startPhaseTimer(workInProgress, "componentWillUpdate"); - instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); - stopPhaseTimer(); } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); + } + stopPhaseTimer(); } if (typeof instance.componentDidUpdate === "function") { workInProgress.effectTag |= Update; @@ -7545,7 +7540,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromText( textContent, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -7573,7 +7568,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromElement( element, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created.ref = coerceRef(current, element); @@ -7592,7 +7587,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromPortal( portal, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -7610,7 +7605,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromFragment( fragment, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, key ); @@ -7631,7 +7626,7 @@ function ChildReconciler(shouldTrackSideEffects) { // node. var created = createFiberFromText( "" + newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -7643,7 +7638,7 @@ function ChildReconciler(shouldTrackSideEffects) { case REACT_ELEMENT_TYPE: { var _created = createFiberFromElement( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); _created.ref = coerceRef(null, newChild); @@ -7653,7 +7648,7 @@ function ChildReconciler(shouldTrackSideEffects) { case REACT_PORTAL_TYPE: { var _created2 = createFiberFromPortal( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); _created2["return"] = returnFiber; @@ -7664,7 +7659,7 @@ function ChildReconciler(shouldTrackSideEffects) { if (isArray$1(newChild) || getIteratorFn(newChild)) { var _created3 = createFiberFromFragment( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, null ); @@ -8248,7 +8243,7 @@ function ChildReconciler(shouldTrackSideEffects) { deleteRemainingChildren(returnFiber, currentFirstChild); var created = createFiberFromText( textContent, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -8300,7 +8295,7 @@ function ChildReconciler(shouldTrackSideEffects) { if (element.type === REACT_FRAGMENT_TYPE) { var created = createFiberFromFragment( element.props.children, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, element.key ); @@ -8309,7 +8304,7 @@ function ChildReconciler(shouldTrackSideEffects) { } else { var _created4 = createFiberFromElement( element, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); _created4.ref = coerceRef(currentFirstChild, element); @@ -8351,7 +8346,7 @@ function ChildReconciler(shouldTrackSideEffects) { var created = createFiberFromPortal( portal, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -8577,6 +8572,7 @@ function resetProviderStack() { context._currentRenderer = null; } } + index$1 = -1; } var didWarnAboutBadClass = void 0; @@ -8795,7 +8791,7 @@ var ReactFiberBeginWork = function( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { instance.render(); } @@ -8931,7 +8927,7 @@ var ReactFiberBeginWork = function( // Check the host config to see if the children are offscreen/hidden. if ( renderExpirationTime !== Never && - workInProgress.internalContextTag & AsyncUpdates && + workInProgress.mode & AsyncMode && shouldDeprioritizeSubtree(type, nextProps) ) { // Down-prioritize the children. @@ -9169,88 +9165,85 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ) { - if (enableNewContextAPI) { - var _fiber = workInProgress.child; - while (_fiber !== null) { - var nextFiber = void 0; - // Visit this fiber. - switch (_fiber.tag) { - case ContextConsumer: - // Check if the context matches. - var observedBits = _fiber.stateNode | 0; - if (_fiber.type === context && (observedBits & changedBits) !== 0) { - // Update the expiration time of all the ancestors, including - // the alternates. - var node = _fiber; - while (node !== null) { - var alternate = node.alternate; + var fiber = workInProgress.child; + while (fiber !== null) { + var nextFiber = void 0; + // Visit this fiber. + switch (fiber.tag) { + case ContextConsumer: + // Check if the context matches. + var observedBits = fiber.stateNode | 0; + if (fiber.type === context && (observedBits & changedBits) !== 0) { + // Update the expiration time of all the ancestors, including + // the alternates. + var node = fiber; + while (node !== null) { + var alternate = node.alternate; + if ( + node.expirationTime === NoWork || + node.expirationTime > renderExpirationTime + ) { + node.expirationTime = renderExpirationTime; if ( - node.expirationTime === NoWork || - node.expirationTime > renderExpirationTime - ) { - node.expirationTime = renderExpirationTime; - if ( - alternate !== null && - (alternate.expirationTime === NoWork || - alternate.expirationTime > renderExpirationTime) - ) { - alternate.expirationTime = renderExpirationTime; - } - } else if ( alternate !== null && (alternate.expirationTime === NoWork || alternate.expirationTime > renderExpirationTime) ) { alternate.expirationTime = renderExpirationTime; - } else { - // Neither alternate was updated, which means the rest of the - // ancestor path already has sufficient priority. - break; } - node = node["return"]; + } else if ( + alternate !== null && + (alternate.expirationTime === NoWork || + alternate.expirationTime > renderExpirationTime) + ) { + alternate.expirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; } - // Don't scan deeper than a matching consumer. When we render the - // consumer, we'll continue scanning from that point. This way the - // scanning work is time-sliced. - nextFiber = null; - } else { - // Traverse down. - nextFiber = _fiber.child; + node = node["return"]; } - break; - case ContextProvider: - // Don't scan deeper if this is a matching provider - nextFiber = - _fiber.type === workInProgress.type ? null : _fiber.child; - break; - default: + // Don't scan deeper than a matching consumer. When we render the + // consumer, we'll continue scanning from that point. This way the + // scanning work is time-sliced. + nextFiber = null; + } else { // Traverse down. - nextFiber = _fiber.child; - break; - } - if (nextFiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - nextFiber["return"] = _fiber; - } else { - // No child. Traverse to next sibling. - nextFiber = _fiber; - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } - var sibling = nextFiber.sibling; - if (sibling !== null) { - nextFiber = sibling; - break; - } - // No more siblings. Traverse up. - nextFiber = nextFiber["return"]; + nextFiber = fiber.child; } - } - _fiber = nextFiber; + break; + case ContextProvider: + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + // Traverse down. + nextFiber = fiber.child; + break; } + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber["return"] = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } + var sibling = nextFiber.sibling; + if (sibling !== null) { + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber["return"]; + } + } + fiber = nextFiber; } } @@ -9259,79 +9252,75 @@ var ReactFiberBeginWork = function( workInProgress, renderExpirationTime ) { - if (enableNewContextAPI) { - var providerType = workInProgress.type; - var context = providerType.context; + var providerType = workInProgress.type; + var context = providerType.context; - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (oldProps === newProps) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - workInProgress.memoizedProps = newProps; + if (hasContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (oldProps === newProps) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + workInProgress.memoizedProps = newProps; - var newValue = newProps.value; + var newValue = newProps.value; - var changedBits = void 0; - if (oldProps === null) { - // Initial render - changedBits = MAX_SIGNED_31_BIT_INT; + var changedBits = void 0; + if (oldProps === null) { + // Initial render + changedBits = MAX_SIGNED_31_BIT_INT; + } else { + var oldValue = oldProps.value; + // Use Object.is to compare the new context value to the old value. + // Inlined Object.is polyfill. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + if ( + (oldValue === newValue && + (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare + ) { + // No change. + changedBits = 0; } else { - var oldValue = oldProps.value; - // Use Object.is to compare the new context value to the old value. - // Inlined Object.is polyfill. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - if ( - (oldValue === newValue && - (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare - ) { - // No change. - changedBits = 0; - } else { - changedBits = - context.calculateChangedBits !== null - ? context.calculateChangedBits(oldValue, newValue) - : MAX_SIGNED_31_BIT_INT; - { - warning( - (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ); - } - changedBits |= 0; + changedBits = + typeof context.calculateChangedBits === "function" + ? context.calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + { + warning( + (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ); + } + changedBits |= 0; - if (changedBits !== 0) { - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } + if (changedBits !== 0) { + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); } } - - workInProgress.stateNode = changedBits; - pushProvider(workInProgress); - - if (oldProps !== null && oldProps.children === newProps.children) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } else { - return null; } + + workInProgress.stateNode = changedBits; + pushProvider(workInProgress); + + if (oldProps !== null && oldProps.children === newProps.children) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; } function updateContextConsumer( @@ -9339,38 +9328,35 @@ var ReactFiberBeginWork = function( workInProgress, renderExpirationTime ) { - if (enableNewContextAPI) { - var context = workInProgress.type; - var newProps = workInProgress.pendingProps; + var context = workInProgress.type; + var newProps = workInProgress.pendingProps; - var newValue = context.currentValue; - var changedBits = context.changedBits; + var newValue = context.currentValue; + var changedBits = context.changedBits; - if (changedBits !== 0) { - // Context change propagation stops at matching consumers, for time- - // slicing. Continue the propagation here. - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } - - // Store the observedBits on the fiber's stateNode for quick access. - var observedBits = newProps.observedBits; - if (observedBits === undefined || observedBits === null) { - // Subscribe to all changes by default - observedBits = MAX_SIGNED_31_BIT_INT; - } - workInProgress.stateNode = observedBits; - - var newChildren = newProps.render(newValue); - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } else { - return null; + if (changedBits !== 0) { + // Context change propagation stops at matching consumers, for time- + // slicing. Continue the propagation here. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); } + + // Store the observedBits on the fiber's stateNode for quick access. + var observedBits = newProps.observedBits; + if (observedBits === undefined || observedBits === null) { + // Subscribe to all changes by default + observedBits = MAX_SIGNED_31_BIT_INT; + } + workInProgress.stateNode = observedBits; + + var render = newProps.children; + var newChildren = render(newValue); + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; } /* @@ -11581,7 +11567,7 @@ var ReactFiberScheduler = function(config) { firstEffect = finishedWork.firstEffect; } - prepareForCommit(); + prepareForCommit(root.containerInfo); // Commit all the side-effects within a tree. We'll do this in two passes. // The first pass performs all the host insertions, updates, deletions and @@ -11613,7 +11599,7 @@ var ReactFiberScheduler = function(config) { } stopCommitHostEffectsTimer(); - resetAfterCommit(); + resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after // the first pass of the commit phase, so that the previous tree is still @@ -11873,23 +11859,16 @@ var ReactFiberScheduler = function(config) { return next; } - function workLoop(expirationTime) { + function workLoop(isAsync) { if (capturedErrors !== null) { // If there are unhandled errors, switch to the slow work loop. // TODO: How to avoid this check in the fast path? Maybe the renderer // could keep track of which roots have unhandled errors and call a // forked version of renderRoot. - slowWorkLoopThatChecksForFailedWork(expirationTime); + slowWorkLoopThatChecksForFailedWork(isAsync); return; } - if ( - nextRenderExpirationTime === NoWork || - nextRenderExpirationTime > expirationTime - ) { - return; - } - - if (nextRenderExpirationTime <= mostRecentCurrentTime) { + if (!isAsync) { // Flush all expired work. while (nextUnitOfWork !== null) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); @@ -11902,15 +11881,8 @@ var ReactFiberScheduler = function(config) { } } - function slowWorkLoopThatChecksForFailedWork(expirationTime) { - if ( - nextRenderExpirationTime === NoWork || - nextRenderExpirationTime > expirationTime - ) { - return; - } - - if (nextRenderExpirationTime <= mostRecentCurrentTime) { + function slowWorkLoopThatChecksForFailedWork(isAsync) { + if (!isAsync) { // Flush all expired work. while (nextUnitOfWork !== null) { if (hasCapturedError(nextUnitOfWork)) { @@ -11933,7 +11905,7 @@ var ReactFiberScheduler = function(config) { } } - function renderRootCatchBlock(root, failedWork, boundary, expirationTime) { + function renderRootCatchBlock(root, failedWork, boundary, isAsync) { // We're going to restart the error boundary that captured the error. // Conceptually, we're unwinding the stack. We need to unwind the // context stack, too. @@ -11947,10 +11919,10 @@ var ReactFiberScheduler = function(config) { nextUnitOfWork = performFailedUnitOfWork(boundary); // Continue working. - workLoop(expirationTime); + workLoop(isAsync); } - function renderRoot(root, expirationTime) { + function renderRoot(root, expirationTime, isAsync) { invariant( !isWorking, "renderRoot was called recursively. This error is likely caused " + @@ -11985,7 +11957,7 @@ var ReactFiberScheduler = function(config) { var didError = false; var error = null; { - invokeGuardedCallback$2(null, workLoop, null, expirationTime); + invokeGuardedCallback$2(null, workLoop, null, isAsync); if (hasCaughtError()) { didError = true; error = clearCaughtError(); @@ -12033,7 +12005,7 @@ var ReactFiberScheduler = function(config) { root, failedWork, boundary, - expirationTime + isAsync ); if (hasCaughtError()) { didError = true; @@ -12314,6 +12286,14 @@ var ReactFiberScheduler = function(config) { return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); } + function computeInteractiveExpiration() { + // Should complete within ~500ms. 600ms max. + var currentTime = recalculateCurrentTime(); + var expirationMs = 500; + var bucketSizeMs = 100; + return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); + } + // Creates a unique async expiration time. function computeUniqueAsyncExpiration() { var result = computeAsyncExpiration(); @@ -12345,14 +12325,30 @@ var ReactFiberScheduler = function(config) { } else { // No explicit expiration context was set, and we're not currently // performing work. Calculate a new expiration time. - if (fiber.internalContextTag & AsyncUpdates) { - // This is an async update - expirationTime = computeAsyncExpiration(); + if (fiber.mode & AsyncMode) { + if (isBatchingInteractiveUpdates) { + // This is an interactive update + expirationTime = computeInteractiveExpiration(); + } else { + // This is an async update + expirationTime = computeAsyncExpiration(); + } } else { // This is a sync update expirationTime = Sync; } } + if (isBatchingInteractiveUpdates) { + // This is an interactive update. Keep track of the lowest pending + // interactive expiration time. This allows us to synchronously flush + // all interactive updates when needed. + if ( + lowestPendingInteractiveExpirationTime === NoWork || + expirationTime > lowestPendingInteractiveExpirationTime + ) { + lowestPendingInteractiveExpirationTime = expirationTime; + } + } return expirationTime; } @@ -12446,11 +12442,11 @@ var ReactFiberScheduler = function(config) { } } - function syncUpdates(fn) { + function syncUpdates(fn, a, b, c, d) { var previousExpirationContext = expirationContext; expirationContext = Sync; try { - return fn(); + return fn(a, b, c, d); } finally { expirationContext = previousExpirationContext; } @@ -12468,6 +12464,7 @@ var ReactFiberScheduler = function(config) { var isRendering = false; var nextFlushedRoot = null; var nextFlushedExpirationTime = NoWork; + var lowestPendingInteractiveExpirationTime = NoWork; var deadlineDidExpire = false; var hasUnhandledError = false; var unhandledError = null; @@ -12475,6 +12472,7 @@ var ReactFiberScheduler = function(config) { var isBatchingUpdates = false; var isUnbatchingUpdates = false; + var isBatchingInteractiveUpdates = false; var completedBatches = null; @@ -12556,20 +12554,20 @@ var ReactFiberScheduler = function(config) { } if (isBatchingUpdates) { - // Flush work at the end of the batch. if (isUnbatchingUpdates) { + // Flush work at the end of the batch. // ...unless we're inside unbatchedUpdates, in which case we should // flush it now. nextFlushedRoot = root; nextFlushedExpirationTime = Sync; - performWorkOnRoot(root, Sync, recalculateCurrentTime()); + performWorkOnRoot(root, Sync, false); } return; } // TODO: Get rid of Sync and use current time? if (expirationTime === Sync) { - performWork(Sync, null); + performSyncWork(); } else { scheduleCallbackWithExpiration(expirationTime); } @@ -12652,10 +12650,14 @@ var ReactFiberScheduler = function(config) { } function performAsyncWork(dl) { - performWork(NoWork, dl); + performWork(NoWork, true, dl); } - function performWork(minExpirationTime, dl) { + function performSyncWork() { + performWork(Sync, false, null); + } + + function performWork(minExpirationTime, isAsync, dl) { deadline = dl; // Keep working on roots until there's no more work, or until the we reach @@ -12667,20 +12669,32 @@ var ReactFiberScheduler = function(config) { stopRequestCallbackTimer(didExpire); } - while ( - nextFlushedRoot !== null && - nextFlushedExpirationTime !== NoWork && - (minExpirationTime === NoWork || - nextFlushedExpirationTime <= minExpirationTime) && - !deadlineDidExpire - ) { - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - recalculateCurrentTime() - ); - // Find the next highest priority work. - findHighestPriorityRoot(); + if (isAsync) { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime) + ) { + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ); + findHighestPriorityRoot(); + } + } else { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) + ) { + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); + findHighestPriorityRoot(); + } } // We're done flushing work. Either we ran out of time in this callback, @@ -12713,7 +12727,7 @@ var ReactFiberScheduler = function(config) { // Perform work on root as if the given expiration time is the current time. // This has the effect of synchronously flushing all work up to and // including the given time. - performWorkOnRoot(root, expirationTime, expirationTime); + performWorkOnRoot(root, expirationTime, false); finishRendering(); } @@ -12742,7 +12756,7 @@ var ReactFiberScheduler = function(config) { } } - function performWorkOnRoot(root, expirationTime, currentTime) { + function performWorkOnRoot(root, expirationTime, isAsync) { invariant( !isRendering, "performWorkOnRoot was called recursively. This error is likely caused " + @@ -12752,7 +12766,7 @@ var ReactFiberScheduler = function(config) { isRendering = true; // Check if this is async work or sync/expired work. - if (expirationTime <= currentTime) { + if (!isAsync) { // Flush sync work. var finishedWork = root.finishedWork; if (finishedWork !== null) { @@ -12760,7 +12774,7 @@ var ReactFiberScheduler = function(config) { completeRoot(root, finishedWork, expirationTime); } else { root.finishedWork = null; - finishedWork = renderRoot(root, expirationTime); + finishedWork = renderRoot(root, expirationTime, false); if (finishedWork !== null) { // We've completed the root. Commit it. completeRoot(root, finishedWork, expirationTime); @@ -12774,7 +12788,7 @@ var ReactFiberScheduler = function(config) { completeRoot(root, _finishedWork, expirationTime); } else { root.finishedWork = null; - _finishedWork = renderRoot(root, expirationTime); + _finishedWork = renderRoot(root, expirationTime, true); if (_finishedWork !== null) { // We've completed the root. Check the deadline one more time // before committing. @@ -12858,40 +12872,93 @@ var ReactFiberScheduler = function(config) { } finally { isBatchingUpdates = previousIsBatchingUpdates; if (!isBatchingUpdates && !isRendering) { - performWork(Sync, null); + performSyncWork(); } } } // TODO: Batching should be implemented at the renderer level, not inside // the reconciler. - function unbatchedUpdates(fn) { + function unbatchedUpdates(fn, a) { if (isBatchingUpdates && !isUnbatchingUpdates) { isUnbatchingUpdates = true; try { - return fn(); + return fn(a); } finally { isUnbatchingUpdates = false; } } - return fn(); + return fn(a); } // TODO: Batching should be implemented at the renderer level, not within // the reconciler. - function flushSync(fn) { + function flushSync(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be " + + "called when React is already rendering." + ); var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = true; try { - return syncUpdates(fn); + return syncUpdates(fn, a); } finally { isBatchingUpdates = previousIsBatchingUpdates; - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be " + - "called when React is already rendering." - ); - performWork(Sync, null); + performSyncWork(); + } + } + + function interactiveUpdates(fn, a, b) { + if (isBatchingInteractiveUpdates) { + return fn(a, b); + } + // If there are any pending interactive updates, synchronously flush them. + // This needs to happen before we read any handlers, because the effect of + // the previous event may influence which handlers are called during + // this event. + if ( + !isBatchingUpdates && + !isRendering && + lowestPendingInteractiveExpirationTime !== NoWork + ) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates; + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingInteractiveUpdates = true; + isBatchingUpdates = true; + try { + return fn(a, b); + } finally { + isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates; + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } + } + } + + function flushInteractiveUpdates() { + if (!isRendering && lowestPendingInteractiveExpirationTime !== NoWork) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + } + + function flushControlled(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + syncUpdates(fn); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performWork(Sync, false, null); + } } } @@ -12903,7 +12970,11 @@ var ReactFiberScheduler = function(config) { batchedUpdates: batchedUpdates, unbatchedUpdates: unbatchedUpdates, flushSync: flushSync, + flushControlled: flushControlled, deferredUpdates: deferredUpdates, + syncUpdates: syncUpdates, + interactiveUpdates: interactiveUpdates, + flushInteractiveUpdates: flushInteractiveUpdates, computeUniqueAsyncExpiration: computeUniqueAsyncExpiration }; }; @@ -12942,7 +13013,11 @@ var ReactFiberReconciler$1 = function(config) { batchedUpdates = _ReactFiberScheduler.batchedUpdates, unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, flushSync = _ReactFiberScheduler.flushSync, - deferredUpdates = _ReactFiberScheduler.deferredUpdates; + flushControlled = _ReactFiberScheduler.flushControlled, + deferredUpdates = _ReactFiberScheduler.deferredUpdates, + syncUpdates = _ReactFiberScheduler.syncUpdates, + interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates; function scheduleRootUpdate(current, element, expirationTime, callback) { { @@ -13057,6 +13132,14 @@ var ReactFiberReconciler$1 = function(config) { deferredUpdates: deferredUpdates, + syncUpdates: syncUpdates, + + interactiveUpdates: interactiveUpdates, + + flushInteractiveUpdates: flushInteractiveUpdates, + + flushControlled: flushControlled, + flushSync: flushSync, getPublicRootInstance: function(container) { @@ -13358,8 +13441,6 @@ var ReactFabricRenderer = reactReconciler({ } }); -injection$2.injectFiberBatchedUpdates(ReactFabricRenderer.batchedUpdates); - // Module provided by RN: var getInspectorDataForViewTag = void 0; @@ -13504,7 +13585,7 @@ function takeSnapshot(view, options) { injectFindHostInstanceFabric(ReactFabricRenderer.findHostInstance); -injection$2.injectFiberBatchedUpdates(ReactFabricRenderer.batchedUpdates); +injection$2.injectRenderer(ReactFabricRenderer); var roots = new Map(); diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index 0b83b8403..ebac6f4f4 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -1021,35 +1021,32 @@ function restoreStateOfTarget(target) { null.restoreControlledState(target.stateNode, target.type, props); } } -function fiberBatchedUpdates(fn, bookkeeping) { +function _batchedUpdates(fn, bookkeeping) { return fn(bookkeeping); } -var isNestingBatched = !1; +function _flushInteractiveUpdates() {} +var isBatching = !1; function batchedUpdates(fn, bookkeeping) { - if (isNestingBatched) return fiberBatchedUpdates(fn, bookkeeping); - isNestingBatched = !0; + if (isBatching) return fn(bookkeeping); + isBatching = !0; try { - return fiberBatchedUpdates(fn, bookkeeping); + return _batchedUpdates(fn, bookkeeping); } finally { - if ( - ((isNestingBatched = !1), - restoreTarget && - ((bookkeeping = restoreTarget), - (fn = restoreQueue), - (restoreQueue = restoreTarget = null), - restoreStateOfTarget(bookkeeping), - fn)) - ) - for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) - restoreStateOfTarget(fn[bookkeeping]); + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdates(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); } } -var injection$2 = { - injectFiberBatchedUpdates: function(_batchedUpdates) { - fiberBatchedUpdates = _batchedUpdates; - } - }, - ReactNativeTagHandles = { +var ReactNativeTagHandles = { tagsStartAt: 1, tagCount: 1, allocateTag: function() { @@ -1174,6 +1171,7 @@ var hasSymbol = "function" === typeof Symbol && Symbol["for"], : 60108, REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, + REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; function getIteratorFn(maybeIterable) { if (null === maybeIterable || "undefined" === typeof maybeIterable) @@ -1943,7 +1941,7 @@ function invalidateContextProvider(workInProgress, didChange) { } else pop(didPerformWorkStackCursor, workInProgress); push(didPerformWorkStackCursor, didChange, workInProgress); } -function FiberNode(tag, pendingProps, key, internalContextTag) { +function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; this.stateNode = this.type = null; @@ -1952,7 +1950,7 @@ function FiberNode(tag, pendingProps, key, internalContextTag) { this.ref = null; this.pendingProps = pendingProps; this.memoizedState = this.updateQueue = this.memoizedProps = null; - this.internalContextTag = internalContextTag; + this.mode = mode; this.effectTag = 0; this.lastEffect = this.firstEffect = this.nextEffect = null; this.expirationTime = 0; @@ -1965,7 +1963,7 @@ function createWorkInProgress(current, pendingProps, expirationTime) { current.tag, pendingProps, current.key, - current.internalContextTag + current.mode )), (workInProgress.type = current.type), (workInProgress.stateNode = current.stateNode), @@ -1986,7 +1984,7 @@ function createWorkInProgress(current, pendingProps, expirationTime) { workInProgress.ref = current.ref; return workInProgress; } -function createFiberFromElement(element, internalContextTag, expirationTime) { +function createFiberFromElement(element, mode, expirationTime) { var type = element.type, key = element.key; element = element.props; @@ -1999,13 +1997,17 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment( element.children, - internalContextTag, + mode, expirationTime, key ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = 11; + mode |= 3; + break; case REACT_STRICT_MODE_TYPE: fiberTag = 11; - internalContextTag |= 2; + mode |= 2; break; case REACT_CALL_TYPE: fiberTag = 7; @@ -2025,24 +2027,19 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { default: if ("number" === typeof type.tag) return ( - (internalContextTag = type), - (internalContextTag.pendingProps = element), - (internalContextTag.expirationTime = expirationTime), - internalContextTag + (mode = type), + (mode.pendingProps = element), + (mode.expirationTime = expirationTime), + mode ); throwOnInvalidElementType(type, null); } else throwOnInvalidElementType(type, null); } - internalContextTag = new FiberNode( - fiberTag, - element, - key, - internalContextTag - ); - internalContextTag.type = type; - internalContextTag.expirationTime = expirationTime; - return internalContextTag; + mode = new FiberNode(fiberTag, element, key, mode); + mode.type = type; + mode.expirationTime = expirationTime; + return mode; } function throwOnInvalidElementType(type) { invariant( @@ -2052,35 +2049,30 @@ function throwOnInvalidElementType(type) { "" ); } -function createFiberFromFragment( - elements, - internalContextTag, - expirationTime, - key -) { - elements = new FiberNode(10, elements, key, internalContextTag); +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = new FiberNode(10, elements, key, mode); elements.expirationTime = expirationTime; return elements; } -function createFiberFromText(content, internalContextTag, expirationTime) { - content = new FiberNode(6, content, null, internalContextTag); +function createFiberFromText(content, mode, expirationTime) { + content = new FiberNode(6, content, null, mode); content.expirationTime = expirationTime; return content; } -function createFiberFromPortal(portal, internalContextTag, expirationTime) { - internalContextTag = new FiberNode( +function createFiberFromPortal(portal, mode, expirationTime) { + mode = new FiberNode( 4, null !== portal.children ? portal.children : [], portal.key, - internalContextTag + mode ); - internalContextTag.expirationTime = expirationTime; - internalContextTag.stateNode = { + mode.expirationTime = expirationTime; + mode.stateNode = { containerInfo: portal.containerInfo, pendingChildren: null, implementation: portal.implementation }; - return internalContextTag; + return mode; } var onCommitFiberRoot = null, onCommitFiberUnmount = null; @@ -2356,18 +2348,14 @@ function ReactFiberClassComponent( instance.state = workInProgress.memoizedState; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); - null != workInProgress.type && - null != workInProgress.type.prototype && - !0 === workInProgress.type.prototype.unstable_isAsyncReactComponent && - ((workInProgress.internalContextTag |= 1), - (workInProgress.internalContextTag |= 2)); ("function" !== typeof instance.UNSAFE_componentWillMount && "function" !== typeof instance.componentWillMount) || "function" === typeof workInProgress.type.getDerivedStateFromProps || ((unmaskedContext = instance.state), - "function" === typeof instance.componentWillMount - ? instance.componentWillMount() - : instance.UNSAFE_componentWillMount(), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), unmaskedContext !== instance.state && updater.enqueueReplaceState(instance, instance.state, null), (unmaskedContext = workInProgress.updateQueue), @@ -2401,12 +2389,13 @@ function ReactFiberClassComponent( "function" === typeof workInProgress.type.getDerivedStateFromProps || (oldProps === newProps && oldContext === newUnmaskedContext) || ((oldContext = instance.state), - "function" === typeof instance.componentWillReceiveProps - ? instance.componentWillReceiveProps(newProps, newUnmaskedContext) - : instance.UNSAFE_componentWillReceiveProps( - newProps, - newUnmaskedContext - ), + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, newUnmaskedContext), + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps( + newProps, + newUnmaskedContext + ), instance.state !== oldContext && updater.enqueueReplaceState(instance, instance.state, null)); var partialState = void 0; @@ -2477,17 +2466,18 @@ function ReactFiberClassComponent( "function" !== typeof instance.componentWillUpdate) || "function" === typeof workInProgress.type.getDerivedStateFromProps || - ("function" === typeof instance.componentWillUpdate - ? instance.componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - ) - : instance.UNSAFE_componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - )), + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + )), "function" === typeof instance.componentDidUpdate && (workInProgress.effectTag |= 4)) : ("function" !== typeof instance.componentDidUpdate || @@ -2616,7 +2606,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (current = createFiberFromText( textContent, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (current["return"] = returnFiber), @@ -2636,7 +2626,7 @@ function ChildReconciler(shouldTrackSideEffects) { ); expirationTime = createFiberFromElement( element, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); expirationTime.ref = coerceRef(current, element); @@ -2653,7 +2643,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (current = createFiberFromPortal( portal, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (current["return"] = returnFiber), @@ -2668,7 +2658,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (current = createFiberFromFragment( fragment, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, key )), @@ -2684,7 +2674,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (newChild = createFiberFromText( "" + newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (newChild["return"] = returnFiber), @@ -2696,7 +2686,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (expirationTime = createFiberFromElement( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (expirationTime.ref = coerceRef(null, newChild)), @@ -2707,7 +2697,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (newChild = createFiberFromPortal( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (newChild["return"] = returnFiber), @@ -2718,7 +2708,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (newChild = createFiberFromFragment( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, null )), @@ -3058,7 +3048,7 @@ function ChildReconciler(shouldTrackSideEffects) { newChild.type === REACT_FRAGMENT_TYPE ? ((currentFirstChild = createFiberFromFragment( newChild.props.children, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, newChild.key )), @@ -3066,7 +3056,7 @@ function ChildReconciler(shouldTrackSideEffects) { (returnFiber = currentFirstChild)) : ((expirationTime = createFiberFromElement( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (expirationTime.ref = coerceRef(currentFirstChild, newChild)), @@ -3106,7 +3096,7 @@ function ChildReconciler(shouldTrackSideEffects) { } currentFirstChild = createFiberFromPortal( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); currentFirstChild["return"] = returnFiber; @@ -3127,7 +3117,7 @@ function ChildReconciler(shouldTrackSideEffects) { : (deleteRemainingChildren(returnFiber, currentFirstChild), (currentFirstChild = createFiberFromText( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ))), (currentFirstChild["return"] = returnFiber), @@ -3167,6 +3157,13 @@ var reconcileChildFibers = ChildReconciler(!0), mountChildFibers = ChildReconciler(!1), stack = [], index$1 = -1; +function pushProvider(providerFiber) { + index$1 += 1; + stack[index$1] = providerFiber; + var context = providerFiber.type.context; + context.currentValue = providerFiber.pendingProps.value; + context.changedBits = providerFiber.stateNode; +} function popProvider(providerFiber) { stack[index$1] = null; --index$1; @@ -3244,6 +3241,63 @@ function ReactFiberBeginWork( pushTopLevelContextObject(workInProgress, root.context, !1); pushHostContainer(workInProgress, root.containerInfo); } + function propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ) { + for (var fiber = workInProgress.child; null !== fiber; ) { + switch (fiber.tag) { + case 12: + var nextFiber = fiber.stateNode | 0; + if (fiber.type === context && 0 !== (nextFiber & changedBits)) { + for (nextFiber = fiber; null !== nextFiber; ) { + var alternate = nextFiber.alternate; + if ( + 0 === nextFiber.expirationTime || + nextFiber.expirationTime > renderExpirationTime + ) + (nextFiber.expirationTime = renderExpirationTime), + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) && + (alternate.expirationTime = renderExpirationTime); + else if ( + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) + ) + alternate.expirationTime = renderExpirationTime; + else break; + nextFiber = nextFiber["return"]; + } + nextFiber = null; + } else nextFiber = fiber.child; + break; + case 13: + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + nextFiber = fiber.child; + } + if (null !== nextFiber) nextFiber["return"] = fiber; + else + for (nextFiber = fiber; null !== nextFiber; ) { + if (nextFiber === workInProgress) { + nextFiber = null; + break; + } + fiber = nextFiber.sibling; + if (null !== fiber) { + nextFiber = fiber; + break; + } + nextFiber = nextFiber["return"]; + } + fiber = nextFiber; + } + } function bailoutOnAlreadyFinishedWork(current, workInProgress) { invariant( null === current || workInProgress.child === current.child, @@ -3284,11 +3338,7 @@ function ReactFiberBeginWork( ); break; case 13: - (index$1 += 1), - (stack[index$1] = workInProgress), - (current = workInProgress.type.context), - (current.currentValue = workInProgress.pendingProps.value), - (current.changedBits = workInProgress.stateNode); + pushProvider(workInProgress); } return null; } @@ -3467,7 +3517,7 @@ function ReactFiberBeginWork( (workInProgress.effectTag |= 16), markRef(current, workInProgress), 1073741823 !== renderExpirationTime && - workInProgress.internalContextTag & 1 && + workInProgress.mode & 1 && shouldDeprioritizeSubtree(props, fn) ? ((workInProgress.expirationTime = 1073741823), (current = null)) @@ -3574,9 +3624,66 @@ function ReactFiberBeginWork( current ); case 13: - return null; + props = workInProgress.type.context; + fn = workInProgress.pendingProps; + unmaskedContext = workInProgress.memoizedProps; + if (didPerformWorkStackCursor.current || unmaskedContext !== fn) { + workInProgress.memoizedProps = fn; + memoizedProps = fn.value; + if (null === unmaskedContext) memoizedProps = 1073741823; + else { + var oldValue = unmaskedContext.value; + (oldValue === memoizedProps && + (0 !== oldValue || 1 / oldValue === 1 / memoizedProps)) || + (oldValue !== oldValue && memoizedProps !== memoizedProps) + ? (memoizedProps = 0) + : ((memoizedProps = + "function" === typeof props.calculateChangedBits + ? props.calculateChangedBits(oldValue, memoizedProps) + : 1073741823), + (memoizedProps |= 0), + 0 !== memoizedProps && + propagateContextChange( + workInProgress, + props, + memoizedProps, + renderExpirationTime + )); + } + workInProgress.stateNode = memoizedProps; + pushProvider(workInProgress); + null !== unmaskedContext && unmaskedContext.children === fn.children + ? (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )) + : (reconcileChildren(current, workInProgress, fn.children), + (current = workInProgress.child)); + } else + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); + return current; case 12: - return null; + unmaskedContext = workInProgress.type; + fn = workInProgress.pendingProps; + props = unmaskedContext.currentValue; + memoizedProps = unmaskedContext.changedBits; + 0 !== memoizedProps && + propagateContextChange( + workInProgress, + unmaskedContext, + memoizedProps, + renderExpirationTime + ); + renderExpirationTime = fn.observedBits; + if (void 0 === renderExpirationTime || null === renderExpirationTime) + renderExpirationTime = 1073741823; + workInProgress.stateNode = renderExpirationTime; + renderExpirationTime = fn.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + return workInProgress.child; default: invariant( !1, @@ -4509,38 +4616,26 @@ function ReactFiberScheduler(config) { ReactCurrentOwner.current = null; return next; } - function workLoop(expirationTime) { - if (null !== capturedErrors) { - if ( - !( - 0 === nextRenderExpirationTime || - nextRenderExpirationTime > expirationTime - ) - ) - if (nextRenderExpirationTime <= mostRecentCurrentTime) - for (; null !== nextUnitOfWork; ) - nextUnitOfWork = hasCapturedError(nextUnitOfWork) - ? performFailedUnitOfWork(nextUnitOfWork) - : performUnitOfWork(nextUnitOfWork); - else - for (; null !== nextUnitOfWork && !shouldYield(); ) - nextUnitOfWork = hasCapturedError(nextUnitOfWork) - ? performFailedUnitOfWork(nextUnitOfWork) - : performUnitOfWork(nextUnitOfWork); - } else if ( - !( - 0 === nextRenderExpirationTime || - nextRenderExpirationTime > expirationTime - ) - ) - if (nextRenderExpirationTime <= mostRecentCurrentTime) - for (; null !== nextUnitOfWork; ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - else + function workLoop(isAsync) { + if (null !== capturedErrors) + if (isAsync) for (; null !== nextUnitOfWork && !shouldYield(); ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + nextUnitOfWork = hasCapturedError(nextUnitOfWork) + ? performFailedUnitOfWork(nextUnitOfWork) + : performUnitOfWork(nextUnitOfWork); + else + for (; null !== nextUnitOfWork; ) + nextUnitOfWork = hasCapturedError(nextUnitOfWork) + ? performFailedUnitOfWork(nextUnitOfWork) + : performUnitOfWork(nextUnitOfWork); + else if (isAsync) + for (; null !== nextUnitOfWork && !shouldYield(); ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + else + for (; null !== nextUnitOfWork; ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } - function renderRoot(root, expirationTime) { + function renderRoot(root, expirationTime, isAsync) { invariant( !isWorking, "renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." @@ -4562,6 +4657,7 @@ function ReactFiberScheduler(config) { context.changedBits = 0; stack[i] = null; } + index$1 = -1; resetHostContainer(); nextRoot = root; nextRenderExpirationTime = expirationTime; @@ -4571,65 +4667,69 @@ function ReactFiberScheduler(config) { expirationTime ); } - context = !1; - var error = null; + i = !1; + context = null; try { - workLoop(expirationTime); + workLoop(isAsync); } catch (e) { - (context = !0), (error = e); + (i = !0), (context = e); } - for (; context; ) { + for (; i; ) { if (didFatal) { - firstUncaughtError = error; + firstUncaughtError = context; break; } - i = nextUnitOfWork; - if (null === i) didFatal = !0; + expirationTime = nextUnitOfWork; + if (null === expirationTime) didFatal = !0; else { - var boundary = captureError(i, error); + var boundary = captureError(expirationTime, context); invariant( null !== boundary, "Should have found an error boundary. This error is likely caused by a bug in React. Please file an issue." ); if (!didFatal) { try { - context = boundary; - error = expirationTime; - for (boundary = context; null !== i; ) { - switch (i.tag) { + i = boundary; + context = isAsync; + for (boundary = i; null !== expirationTime; ) { + switch (expirationTime.tag) { case 2: - popContextProvider(i); + popContextProvider(expirationTime); break; case 5: - popHostContext(i); + popHostContext(expirationTime); break; case 3: - popHostContainer(i); + popHostContainer(expirationTime); break; case 4: - popHostContainer(i); + popHostContainer(expirationTime); break; case 13: - popProvider(i); + popProvider(expirationTime); } - if (i === boundary || i.alternate === boundary) break; - i = i["return"]; + if ( + expirationTime === boundary || + expirationTime.alternate === boundary + ) + break; + expirationTime = expirationTime["return"]; } - nextUnitOfWork = performFailedUnitOfWork(context); - workLoop(error); + nextUnitOfWork = performFailedUnitOfWork(i); + workLoop(context); } catch (e) { - context = !0; - error = e; + i = !0; + context = e; continue; } break; } } } - expirationTime = firstUncaughtError; + isAsync = firstUncaughtError; didFatal = isWorking = !1; firstUncaughtError = null; - null !== expirationTime && onUncaughtError(expirationTime); + null !== isAsync && onUncaughtError(isAsync); return root.isReadyForCommit ? root.current.alternate : null; } function captureError(failedWork, error$jscomp$0) { @@ -4747,11 +4847,21 @@ function ReactFiberScheduler(config) { return 20 * ((((recalculateCurrentTime() + 100) / 20) | 0) + 1); } function computeExpirationForFiber(fiber) { - return 0 !== expirationContext - ? expirationContext - : isWorking - ? isCommitting ? 1 : nextRenderExpirationTime - : fiber.internalContextTag & 1 ? computeAsyncExpiration() : 1; + fiber = + 0 !== expirationContext + ? expirationContext + : isWorking + ? isCommitting ? 1 : nextRenderExpirationTime + : fiber.mode & 1 + ? isBatchingInteractiveUpdates + ? 10 * ((((recalculateCurrentTime() + 50) / 10) | 0) + 1) + : computeAsyncExpiration() + : 1; + isBatchingInteractiveUpdates && + (0 === lowestPendingInteractiveExpirationTime || + fiber > lowestPendingInteractiveExpirationTime) && + (lowestPendingInteractiveExpirationTime = fiber); + return fiber; } function scheduleWork(fiber, expirationTime) { return scheduleWorkImpl(fiber, expirationTime, !1); @@ -4788,6 +4898,15 @@ function ReactFiberScheduler(config) { function recalculateCurrentTime() { return (mostRecentCurrentTime = (((now() - startTime) / 10) | 0) + 2); } + function syncUpdates(fn, a, b, c, d) { + var previousExpirationContext = expirationContext; + expirationContext = 1; + try { + return fn(a, b, c, d); + } finally { + expirationContext = previousExpirationContext; + } + } function scheduleCallbackWithExpiration(expirationTime) { if (0 !== callbackExpirationTime) { if (expirationTime > callbackExpirationTime) return; @@ -4825,9 +4944,9 @@ function ReactFiberScheduler(config) { ? isUnbatchingUpdates && ((nextFlushedRoot = root), (nextFlushedExpirationTime = 1), - performWorkOnRoot(root, 1, recalculateCurrentTime())) + performWorkOnRoot(root, 1, !1)) : 1 === expirationTime - ? performWork(1, null) + ? performWork(1, !1, null) : scheduleCallbackWithExpiration(expirationTime)); } function findHighestPriorityRoot() { @@ -4884,25 +5003,39 @@ function ReactFiberScheduler(config) { nextFlushedExpirationTime = highestPriorityWork; } function performAsyncWork(dl) { - performWork(0, dl); + performWork(0, !0, dl); } - function performWork(minExpirationTime, dl) { + function performWork(minExpirationTime, isAsync, dl) { deadline = dl; - for ( - findHighestPriorityRoot(); - null !== nextFlushedRoot && - 0 !== nextFlushedExpirationTime && - (0 === minExpirationTime || - nextFlushedExpirationTime <= minExpirationTime) && - !deadlineDidExpire; + findHighestPriorityRoot(); + if (isAsync) + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime); - ) - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - recalculateCurrentTime() - ), - findHighestPriorityRoot(); + ) + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ), + findHighestPriorityRoot(); + else + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime); + + ) + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, !1), + findHighestPriorityRoot(); null !== deadline && ((callbackExpirationTime = 0), (callbackID = -1)); 0 !== nextFlushedExpirationTime && scheduleCallbackWithExpiration(nextFlushedExpirationTime); @@ -4931,29 +5064,28 @@ function ReactFiberScheduler(config) { (hasUnhandledError = !1), batches); } - function performWorkOnRoot(root, expirationTime, currentTime) { + function performWorkOnRoot(root, expirationTime, isAsync) { invariant( !isRendering, "performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." ); isRendering = !0; - expirationTime <= currentTime - ? ((currentTime = root.finishedWork), - null !== currentTime - ? completeRoot(root, currentTime, expirationTime) + isAsync + ? ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) : ((root.finishedWork = null), - (currentTime = renderRoot(root, expirationTime)), - null !== currentTime && - completeRoot(root, currentTime, expirationTime))) - : ((currentTime = root.finishedWork), - null !== currentTime - ? completeRoot(root, currentTime, expirationTime) - : ((root.finishedWork = null), - (currentTime = renderRoot(root, expirationTime)), - null !== currentTime && + (isAsync = renderRoot(root, expirationTime, !0)), + null !== isAsync && (shouldYield() - ? (root.finishedWork = currentTime) - : completeRoot(root, currentTime, expirationTime)))); + ? (root.finishedWork = isAsync) + : completeRoot(root, isAsync, expirationTime)))) + : ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) + : ((root.finishedWork = null), + (isAsync = renderRoot(root, expirationTime, !1)), + null !== isAsync && completeRoot(root, isAsync, expirationTime))); isRendering = !1; } function completeRoot(root, finishedWork, expirationTime) { @@ -4985,7 +5117,7 @@ function ReactFiberScheduler(config) { (firstBatch = finishedWork.firstEffect)) : (firstBatch = finishedWork) : (firstBatch = finishedWork.firstEffect); - prepareForCommit(); + prepareForCommit(expirationTime.containerInfo); for (nextEffect = firstBatch; null !== nextEffect; ) { var didError = !1, _error = void 0; @@ -5028,7 +5160,7 @@ function ReactFiberScheduler(config) { captureError(nextEffect, _error), null !== nextEffect && (nextEffect = nextEffect.nextEffect)); } - resetAfterCommit(); + resetAfterCommit(expirationTime.containerInfo); expirationTime.current = finishedWork; for (nextEffect = firstBatch; null !== nextEffect; ) { effectTag = !1; @@ -5164,12 +5296,14 @@ function ReactFiberScheduler(config) { isRendering = !1, nextFlushedRoot = null, nextFlushedExpirationTime = 0, + lowestPendingInteractiveExpirationTime = 0, deadlineDidExpire = !1, hasUnhandledError = !1, unhandledError = null, deadline = null, isBatchingUpdates = !1, isUnbatchingUpdates = !1, + isBatchingInteractiveUpdates = !1, completedBatches = null, NESTED_UPDATE_LIMIT = 1e3, nestedUpdateCount = 0, @@ -5183,7 +5317,7 @@ function ReactFiberScheduler(config) { !isRendering, "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." ); - performWorkOnRoot(root, expirationTime, expirationTime); + performWorkOnRoot(root, expirationTime, !1); finishRendering(); }, batchedUpdates: function(fn, a) { @@ -5194,43 +5328,43 @@ function ReactFiberScheduler(config) { } finally { (isBatchingUpdates = previousIsBatchingUpdates) || isRendering || - performWork(1, null); + performWork(1, !1, null); } }, - unbatchedUpdates: function(fn) { + unbatchedUpdates: function(fn, a) { if (isBatchingUpdates && !isUnbatchingUpdates) { isUnbatchingUpdates = !0; try { - return fn(); + return fn(a); } finally { isUnbatchingUpdates = !1; } } - return fn(); + return fn(a); }, - flushSync: function(fn) { + flushSync: function(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." + ); var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = !0; try { - a: { - var previousExpirationContext = expirationContext; - expirationContext = 1; - try { - var JSCompiler_inline_result = fn(); - break a; - } finally { - expirationContext = previousExpirationContext; - } - JSCompiler_inline_result = void 0; - } - return JSCompiler_inline_result; + return syncUpdates(fn, a); } finally { (isBatchingUpdates = previousIsBatchingUpdates), - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." - ), - performWork(1, null); + performWork(1, !1, null); + } + }, + flushControlled: function(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + syncUpdates(fn); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performWork(1, !1, null); } }, deferredUpdates: function(fn) { @@ -5242,6 +5376,32 @@ function ReactFiberScheduler(config) { expirationContext = previousExpirationContext; } }, + syncUpdates: syncUpdates, + interactiveUpdates: function(fn, a, b) { + if (isBatchingInteractiveUpdates) return fn(a, b); + isBatchingUpdates || + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates, + previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = isBatchingInteractiveUpdates = !0; + try { + return fn(a, b); + } finally { + (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performWork(1, !1, null); + } + }, + flushInteractiveUpdates: function() { + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + }, computeUniqueAsyncExpiration: function() { var result = computeAsyncExpiration(); result <= lastUniqueAsyncExpiration && @@ -5344,6 +5504,10 @@ function ReactFiberReconciler$1(config) { batchedUpdates: config.batchedUpdates, unbatchedUpdates: config.unbatchedUpdates, deferredUpdates: config.deferredUpdates, + syncUpdates: config.syncUpdates, + interactiveUpdates: config.interactiveUpdates, + flushInteractiveUpdates: config.flushInteractiveUpdates, + flushControlled: config.flushControlled, flushSync: config.flushSync, getPublicRootInstance: function(container) { container = container.current; @@ -5566,14 +5730,14 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), }, replaceContainerChildren: function() {} } - }); -injection$2.injectFiberBatchedUpdates(ReactFabricRenderer.batchedUpdates); -var getInspectorDataForViewTag = void 0; + }), + getInspectorDataForViewTag = void 0; getInspectorDataForViewTag = function() { invariant(!1, "getInspectorDataForViewTag() is not available in production"); }; findHostInstanceFabric = ReactFabricRenderer.findHostInstance; -injection$2.injectFiberBatchedUpdates(ReactFabricRenderer.batchedUpdates); +_batchedUpdates = ReactFabricRenderer.batchedUpdates; +_flushInteractiveUpdates = ReactFabricRenderer.flushInteractiveUpdates; var roots = new Map(), ReactFabric = { NativeComponent: ReactNativeComponent, diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index 64ed9dba8..48a3d1767 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -2550,6 +2550,10 @@ function restoreStateOfTarget(target) { ); } +function needsStateRestore() { + return restoreTarget !== null || restoreQueue !== null; +} + function restoreStateIfNeeded() { if (!restoreTarget) { return; @@ -2574,39 +2578,49 @@ function restoreStateIfNeeded() { // scheduled work and instead do synchronous work. // Defaults -var fiberBatchedUpdates = function(fn, bookkeeping) { +var _batchedUpdates = function(fn, bookkeeping) { return fn(bookkeeping); }; +var _interactiveUpdates = function(fn, a, b) { + return fn(a, b); +}; +var _flushInteractiveUpdates = function() {}; -var isNestingBatched = false; +var isBatching = false; function batchedUpdates(fn, bookkeeping) { - if (isNestingBatched) { + if (isBatching) { // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. Therefore, we add the target to - // a queue of work. - return fiberBatchedUpdates(fn, bookkeeping); + // fully completes before restoring state. + return fn(bookkeeping); } - isNestingBatched = true; + isBatching = true; try { - return fiberBatchedUpdates(fn, bookkeeping); + return _batchedUpdates(fn, bookkeeping); } finally { // Here we wait until all updates have propagated, which is important // when using controlled components within layers: // https://github.com/facebook/react/issues/1698 // Then we restore state of any controlled component. - isNestingBatched = false; - restoreStateIfNeeded(); + isBatching = false; + var controlledComponentsHavePendingUpdates = needsStateRestore(); + if (controlledComponentsHavePendingUpdates) { + // If a controlled event was fired, we may need to restore the state of + // the DOM node back to the controlled value. This is necessary when React + // bails out of the update without touching the DOM. + _flushInteractiveUpdates(); + restoreStateIfNeeded(); + } } } -var ReactGenericBatchingInjection = { - injectFiberBatchedUpdates: function(_batchedUpdates) { - fiberBatchedUpdates = _batchedUpdates; +var injection$2 = { + injectRenderer: function(renderer) { + _batchedUpdates = renderer.batchedUpdates; + _interactiveUpdates = renderer.interactiveUpdates; + _flushInteractiveUpdates = renderer.flushInteractiveUpdates; } }; -var injection$2 = ReactGenericBatchingInjection; - /** * Keeps track of allocating and associating native "tags" which are numeric, * unique view IDs. All the native tags are negative numbers, to avoid @@ -2868,6 +2882,9 @@ var REACT_STRICT_MODE_TYPE = hasSymbol : 0xeacc; var REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 0xeacd; var REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 0xeace; +var REACT_ASYNC_MODE_TYPE = hasSymbol + ? Symbol["for"]("react.async_mode") + : 0xeacf; var MAYBE_ITERATOR_SYMBOL = typeof Symbol === "function" && Symbol.iterator; var FAUX_ITERATOR_SYMBOL = "@@iterator"; @@ -4609,13 +4626,10 @@ var debugRenderPhaseSideEffectsForStrictMode = _require.debugRenderPhaseSideEffectsForStrictMode; var warnAboutDeprecatedLifecycles = _require.warnAboutDeprecatedLifecycles; -var enableAsyncSubtreeAPI = true; - var enableUserTimingAPI = true; var enableMutatingReconciler = true; var enableNoopReconciler = false; var enablePersistentReconciler = false; -var enableNewContextAPI = false; // Only used in www builds. @@ -5343,7 +5357,7 @@ function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { } var NoContext = 0; -var AsyncUpdates = 1; +var AsyncMode = 1; var StrictMode = 2; var hasBadMapPolyfill = void 0; @@ -5374,7 +5388,7 @@ var debugCounter = void 0; debugCounter = 1; } -function FiberNode(tag, pendingProps, key, internalContextTag) { +function FiberNode(tag, pendingProps, key, mode) { // Instance this.tag = tag; this.key = key; @@ -5394,7 +5408,7 @@ function FiberNode(tag, pendingProps, key, internalContextTag) { this.updateQueue = null; this.memoizedState = null; - this.internalContextTag = internalContextTag; + this.mode = mode; // Effects this.effectTag = NoEffect; @@ -5431,9 +5445,9 @@ function FiberNode(tag, pendingProps, key, internalContextTag) { // is faster. // 5) It should be easy to port this to a C struct and keep a C implementation // compatible. -var createFiber = function(tag, pendingProps, key, internalContextTag) { +var createFiber = function(tag, pendingProps, key, mode) { // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors - return new FiberNode(tag, pendingProps, key, internalContextTag); + return new FiberNode(tag, pendingProps, key, mode); }; function shouldConstruct(Component) { @@ -5453,7 +5467,7 @@ function createWorkInProgress(current, pendingProps, expirationTime) { current.tag, pendingProps, current.key, - current.internalContextTag + current.mode ); workInProgress.type = current.type; workInProgress.stateNode = current.stateNode; @@ -5496,11 +5510,11 @@ function createWorkInProgress(current, pendingProps, expirationTime) { } function createHostRootFiber(isAsync) { - var internalContextTag = isAsync ? AsyncUpdates | StrictMode : NoContext; - return createFiber(HostRoot, null, null, internalContextTag); + var mode = isAsync ? AsyncMode | StrictMode : NoContext; + return createFiber(HostRoot, null, null, mode); } -function createFiberFromElement(element, internalContextTag, expirationTime) { +function createFiberFromElement(element, mode, expirationTime) { var owner = null; { owner = element._owner; @@ -5521,13 +5535,17 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment( pendingProps.children, - internalContextTag, + mode, expirationTime, key ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = Mode; + mode |= AsyncMode | StrictMode; + break; case REACT_STRICT_MODE_TYPE: fiberTag = Mode; - internalContextTag |= StrictMode; + mode |= StrictMode; break; case REACT_CALL_TYPE: fiberTag = CallComponent; @@ -5571,7 +5589,7 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { } } - fiber = createFiber(fiberTag, pendingProps, key, internalContextTag); + fiber = createFiber(fiberTag, pendingProps, key, mode); fiber.type = type; fiber.expirationTime = expirationTime; @@ -5612,19 +5630,14 @@ function throwOnInvalidElementType(type, owner) { ); } -function createFiberFromFragment( - elements, - internalContextTag, - expirationTime, - key -) { - var fiber = createFiber(Fragment, elements, key, internalContextTag); +function createFiberFromFragment(elements, mode, expirationTime, key) { + var fiber = createFiber(Fragment, elements, key, mode); fiber.expirationTime = expirationTime; return fiber; } -function createFiberFromText(content, internalContextTag, expirationTime) { - var fiber = createFiber(HostText, content, null, internalContextTag); +function createFiberFromText(content, mode, expirationTime) { + var fiber = createFiber(HostText, content, null, mode); fiber.expirationTime = expirationTime; return fiber; } @@ -5635,14 +5648,9 @@ function createFiberFromHostInstanceForDeletion() { return fiber; } -function createFiberFromPortal(portal, internalContextTag, expirationTime) { +function createFiberFromPortal(portal, mode, expirationTime) { var pendingProps = portal.children !== null ? portal.children : []; - var fiber = createFiber( - HostPortal, - pendingProps, - portal.key, - internalContextTag - ); + var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); fiber.expirationTime = expirationTime; fiber.stateNode = { containerInfo: portal.containerInfo, @@ -5832,7 +5840,7 @@ var ReactStrictModeWarnings = { var maybeStrictRoot = null; while (fiber !== null) { - if (fiber.internalContextTag & StrictMode) { + if (fiber.mode & StrictMode) { maybeStrictRoot = fiber; } @@ -6233,7 +6241,7 @@ function processUpdateQueue( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { getStateFromUpdate(update, instance, state, props); } @@ -6667,7 +6675,7 @@ var ReactFiberClassComponent = function( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { new ctor(props, context); // eslint-disable-line no-new } @@ -6732,7 +6740,8 @@ var ReactFiberClassComponent = function( if (typeof instance.componentWillMount === "function") { instance.componentWillMount(); - } else { + } + if (typeof instance.UNSAFE_componentWillMount === "function") { instance.UNSAFE_componentWillMount(); } @@ -6759,15 +6768,14 @@ var ReactFiberClassComponent = function( newContext ) { var oldState = instance.state; + startPhaseTimer(workInProgress, "componentWillReceiveProps"); if (typeof instance.componentWillReceiveProps === "function") { - startPhaseTimer(workInProgress, "componentWillReceiveProps"); instance.componentWillReceiveProps(newProps, newContext); - stopPhaseTimer(); - } else { - startPhaseTimer(workInProgress, "componentWillReceiveProps"); - instance.UNSAFE_componentWillReceiveProps(newProps, newContext); - stopPhaseTimer(); } + if (typeof instance.UNSAFE_componentWillReceiveProps === "function") { + instance.UNSAFE_componentWillReceiveProps(newProps, newContext); + } + stopPhaseTimer(); if (instance.state !== oldState) { { @@ -6816,7 +6824,7 @@ var ReactFiberClassComponent = function( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { // Invoke method an extra time to help detect side-effects. type.getDerivedStateFromProps.call( @@ -6868,19 +6876,8 @@ var ReactFiberClassComponent = function( instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); - if (workInProgress.type != null && workInProgress.type.prototype != null) { - var prototype = workInProgress.type.prototype; - - if (enableAsyncSubtreeAPI) { - if (prototype.unstable_isAsyncReactComponent === true) { - workInProgress.internalContextTag |= AsyncUpdates; - workInProgress.internalContextTag |= StrictMode; - } - } - } - { - if (workInProgress.internalContextTag & StrictMode) { + if (workInProgress.mode & StrictMode) { ReactStrictModeWarnings.recordUnsafeLifecycleWarnings( workInProgress, instance @@ -7134,15 +7131,14 @@ var ReactFiberClassComponent = function( typeof instance.componentWillUpdate === "function") && typeof workInProgress.type.getDerivedStateFromProps !== "function" ) { + startPhaseTimer(workInProgress, "componentWillUpdate"); if (typeof instance.componentWillUpdate === "function") { - startPhaseTimer(workInProgress, "componentWillUpdate"); instance.componentWillUpdate(newProps, newState, newContext); - stopPhaseTimer(); - } else { - startPhaseTimer(workInProgress, "componentWillUpdate"); - instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); - stopPhaseTimer(); } + if (typeof instance.UNSAFE_componentWillUpdate === "function") { + instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); + } + stopPhaseTimer(); } if (typeof instance.componentDidUpdate === "function") { workInProgress.effectTag |= Update; @@ -7444,7 +7440,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromText( textContent, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -7472,7 +7468,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromElement( element, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created.ref = coerceRef(current, element); @@ -7491,7 +7487,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromPortal( portal, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -7509,7 +7505,7 @@ function ChildReconciler(shouldTrackSideEffects) { // Insert var created = createFiberFromFragment( fragment, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, key ); @@ -7530,7 +7526,7 @@ function ChildReconciler(shouldTrackSideEffects) { // node. var created = createFiberFromText( "" + newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -7542,7 +7538,7 @@ function ChildReconciler(shouldTrackSideEffects) { case REACT_ELEMENT_TYPE: { var _created = createFiberFromElement( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); _created.ref = coerceRef(null, newChild); @@ -7552,7 +7548,7 @@ function ChildReconciler(shouldTrackSideEffects) { case REACT_PORTAL_TYPE: { var _created2 = createFiberFromPortal( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); _created2["return"] = returnFiber; @@ -7563,7 +7559,7 @@ function ChildReconciler(shouldTrackSideEffects) { if (isArray$1(newChild) || getIteratorFn(newChild)) { var _created3 = createFiberFromFragment( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, null ); @@ -8147,7 +8143,7 @@ function ChildReconciler(shouldTrackSideEffects) { deleteRemainingChildren(returnFiber, currentFirstChild); var created = createFiberFromText( textContent, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -8199,7 +8195,7 @@ function ChildReconciler(shouldTrackSideEffects) { if (element.type === REACT_FRAGMENT_TYPE) { var created = createFiberFromFragment( element.props.children, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, element.key ); @@ -8208,7 +8204,7 @@ function ChildReconciler(shouldTrackSideEffects) { } else { var _created4 = createFiberFromElement( element, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); _created4.ref = coerceRef(currentFirstChild, element); @@ -8250,7 +8246,7 @@ function ChildReconciler(shouldTrackSideEffects) { var created = createFiberFromPortal( portal, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); created["return"] = returnFiber; @@ -8476,6 +8472,7 @@ function resetProviderStack() { context._currentRenderer = null; } } + index$1 = -1; } var didWarnAboutBadClass = void 0; @@ -8694,7 +8691,7 @@ var ReactFiberBeginWork = function( if ( debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & StrictMode) + workInProgress.mode & StrictMode) ) { instance.render(); } @@ -8830,7 +8827,7 @@ var ReactFiberBeginWork = function( // Check the host config to see if the children are offscreen/hidden. if ( renderExpirationTime !== Never && - workInProgress.internalContextTag & AsyncUpdates && + workInProgress.mode & AsyncMode && shouldDeprioritizeSubtree(type, nextProps) ) { // Down-prioritize the children. @@ -9068,88 +9065,85 @@ var ReactFiberBeginWork = function( changedBits, renderExpirationTime ) { - if (enableNewContextAPI) { - var _fiber = workInProgress.child; - while (_fiber !== null) { - var nextFiber = void 0; - // Visit this fiber. - switch (_fiber.tag) { - case ContextConsumer: - // Check if the context matches. - var observedBits = _fiber.stateNode | 0; - if (_fiber.type === context && (observedBits & changedBits) !== 0) { - // Update the expiration time of all the ancestors, including - // the alternates. - var node = _fiber; - while (node !== null) { - var alternate = node.alternate; + var fiber = workInProgress.child; + while (fiber !== null) { + var nextFiber = void 0; + // Visit this fiber. + switch (fiber.tag) { + case ContextConsumer: + // Check if the context matches. + var observedBits = fiber.stateNode | 0; + if (fiber.type === context && (observedBits & changedBits) !== 0) { + // Update the expiration time of all the ancestors, including + // the alternates. + var node = fiber; + while (node !== null) { + var alternate = node.alternate; + if ( + node.expirationTime === NoWork || + node.expirationTime > renderExpirationTime + ) { + node.expirationTime = renderExpirationTime; if ( - node.expirationTime === NoWork || - node.expirationTime > renderExpirationTime - ) { - node.expirationTime = renderExpirationTime; - if ( - alternate !== null && - (alternate.expirationTime === NoWork || - alternate.expirationTime > renderExpirationTime) - ) { - alternate.expirationTime = renderExpirationTime; - } - } else if ( alternate !== null && (alternate.expirationTime === NoWork || alternate.expirationTime > renderExpirationTime) ) { alternate.expirationTime = renderExpirationTime; - } else { - // Neither alternate was updated, which means the rest of the - // ancestor path already has sufficient priority. - break; } - node = node["return"]; + } else if ( + alternate !== null && + (alternate.expirationTime === NoWork || + alternate.expirationTime > renderExpirationTime) + ) { + alternate.expirationTime = renderExpirationTime; + } else { + // Neither alternate was updated, which means the rest of the + // ancestor path already has sufficient priority. + break; } - // Don't scan deeper than a matching consumer. When we render the - // consumer, we'll continue scanning from that point. This way the - // scanning work is time-sliced. - nextFiber = null; - } else { - // Traverse down. - nextFiber = _fiber.child; + node = node["return"]; } - break; - case ContextProvider: - // Don't scan deeper if this is a matching provider - nextFiber = - _fiber.type === workInProgress.type ? null : _fiber.child; - break; - default: + // Don't scan deeper than a matching consumer. When we render the + // consumer, we'll continue scanning from that point. This way the + // scanning work is time-sliced. + nextFiber = null; + } else { // Traverse down. - nextFiber = _fiber.child; - break; - } - if (nextFiber !== null) { - // Set the return pointer of the child to the work-in-progress fiber. - nextFiber["return"] = _fiber; - } else { - // No child. Traverse to next sibling. - nextFiber = _fiber; - while (nextFiber !== null) { - if (nextFiber === workInProgress) { - // We're back to the root of this subtree. Exit. - nextFiber = null; - break; - } - var sibling = nextFiber.sibling; - if (sibling !== null) { - nextFiber = sibling; - break; - } - // No more siblings. Traverse up. - nextFiber = nextFiber["return"]; + nextFiber = fiber.child; } - } - _fiber = nextFiber; + break; + case ContextProvider: + // Don't scan deeper if this is a matching provider + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + // Traverse down. + nextFiber = fiber.child; + break; } + if (nextFiber !== null) { + // Set the return pointer of the child to the work-in-progress fiber. + nextFiber["return"] = fiber; + } else { + // No child. Traverse to next sibling. + nextFiber = fiber; + while (nextFiber !== null) { + if (nextFiber === workInProgress) { + // We're back to the root of this subtree. Exit. + nextFiber = null; + break; + } + var sibling = nextFiber.sibling; + if (sibling !== null) { + nextFiber = sibling; + break; + } + // No more siblings. Traverse up. + nextFiber = nextFiber["return"]; + } + } + fiber = nextFiber; } } @@ -9158,79 +9152,75 @@ var ReactFiberBeginWork = function( workInProgress, renderExpirationTime ) { - if (enableNewContextAPI) { - var providerType = workInProgress.type; - var context = providerType.context; + var providerType = workInProgress.type; + var context = providerType.context; - var newProps = workInProgress.pendingProps; - var oldProps = workInProgress.memoizedProps; + var newProps = workInProgress.pendingProps; + var oldProps = workInProgress.memoizedProps; - if (hasContextChanged()) { - // Normally we can bail out on props equality but if context has changed - // we don't do the bailout and we have to reuse existing props instead. - } else if (oldProps === newProps) { - workInProgress.stateNode = 0; - pushProvider(workInProgress); - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - workInProgress.memoizedProps = newProps; + if (hasContextChanged()) { + // Normally we can bail out on props equality but if context has changed + // we don't do the bailout and we have to reuse existing props instead. + } else if (oldProps === newProps) { + workInProgress.stateNode = 0; + pushProvider(workInProgress); + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + workInProgress.memoizedProps = newProps; - var newValue = newProps.value; + var newValue = newProps.value; - var changedBits = void 0; - if (oldProps === null) { - // Initial render - changedBits = MAX_SIGNED_31_BIT_INT; + var changedBits = void 0; + if (oldProps === null) { + // Initial render + changedBits = MAX_SIGNED_31_BIT_INT; + } else { + var oldValue = oldProps.value; + // Use Object.is to compare the new context value to the old value. + // Inlined Object.is polyfill. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + if ( + (oldValue === newValue && + (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || + (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare + ) { + // No change. + changedBits = 0; } else { - var oldValue = oldProps.value; - // Use Object.is to compare the new context value to the old value. - // Inlined Object.is polyfill. - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is - if ( - (oldValue === newValue && - (oldValue !== 0 || 1 / oldValue === 1 / newValue)) || - (oldValue !== oldValue && newValue !== newValue) // eslint-disable-line no-self-compare - ) { - // No change. - changedBits = 0; - } else { - changedBits = - context.calculateChangedBits !== null - ? context.calculateChangedBits(oldValue, newValue) - : MAX_SIGNED_31_BIT_INT; - { - warning( - (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, - "calculateChangedBits: Expected the return value to be a " + - "31-bit integer. Instead received: %s", - changedBits - ); - } - changedBits |= 0; + changedBits = + typeof context.calculateChangedBits === "function" + ? context.calculateChangedBits(oldValue, newValue) + : MAX_SIGNED_31_BIT_INT; + { + warning( + (changedBits & MAX_SIGNED_31_BIT_INT) === changedBits, + "calculateChangedBits: Expected the return value to be a " + + "31-bit integer. Instead received: %s", + changedBits + ); + } + changedBits |= 0; - if (changedBits !== 0) { - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } + if (changedBits !== 0) { + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); } } - - workInProgress.stateNode = changedBits; - pushProvider(workInProgress); - - if (oldProps !== null && oldProps.children === newProps.children) { - return bailoutOnAlreadyFinishedWork(current, workInProgress); - } - var newChildren = newProps.children; - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } else { - return null; } + + workInProgress.stateNode = changedBits; + pushProvider(workInProgress); + + if (oldProps !== null && oldProps.children === newProps.children) { + return bailoutOnAlreadyFinishedWork(current, workInProgress); + } + var newChildren = newProps.children; + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; } function updateContextConsumer( @@ -9238,38 +9228,35 @@ var ReactFiberBeginWork = function( workInProgress, renderExpirationTime ) { - if (enableNewContextAPI) { - var context = workInProgress.type; - var newProps = workInProgress.pendingProps; + var context = workInProgress.type; + var newProps = workInProgress.pendingProps; - var newValue = context.currentValue; - var changedBits = context.changedBits; + var newValue = context.currentValue; + var changedBits = context.changedBits; - if (changedBits !== 0) { - // Context change propagation stops at matching consumers, for time- - // slicing. Continue the propagation here. - propagateContextChange( - workInProgress, - context, - changedBits, - renderExpirationTime - ); - } - - // Store the observedBits on the fiber's stateNode for quick access. - var observedBits = newProps.observedBits; - if (observedBits === undefined || observedBits === null) { - // Subscribe to all changes by default - observedBits = MAX_SIGNED_31_BIT_INT; - } - workInProgress.stateNode = observedBits; - - var newChildren = newProps.render(newValue); - reconcileChildren(current, workInProgress, newChildren); - return workInProgress.child; - } else { - return null; + if (changedBits !== 0) { + // Context change propagation stops at matching consumers, for time- + // slicing. Continue the propagation here. + propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ); } + + // Store the observedBits on the fiber's stateNode for quick access. + var observedBits = newProps.observedBits; + if (observedBits === undefined || observedBits === null) { + // Subscribe to all changes by default + observedBits = MAX_SIGNED_31_BIT_INT; + } + workInProgress.stateNode = observedBits; + + var render = newProps.children; + var newChildren = render(newValue); + reconcileChildren(current, workInProgress, newChildren); + return workInProgress.child; } /* @@ -11514,7 +11501,7 @@ var ReactFiberScheduler = function(config) { firstEffect = finishedWork.firstEffect; } - prepareForCommit(); + prepareForCommit(root.containerInfo); // Commit all the side-effects within a tree. We'll do this in two passes. // The first pass performs all the host insertions, updates, deletions and @@ -11546,7 +11533,7 @@ var ReactFiberScheduler = function(config) { } stopCommitHostEffectsTimer(); - resetAfterCommit(); + resetAfterCommit(root.containerInfo); // The work-in-progress tree is now the current tree. This must come after // the first pass of the commit phase, so that the previous tree is still @@ -11806,23 +11793,16 @@ var ReactFiberScheduler = function(config) { return next; } - function workLoop(expirationTime) { + function workLoop(isAsync) { if (capturedErrors !== null) { // If there are unhandled errors, switch to the slow work loop. // TODO: How to avoid this check in the fast path? Maybe the renderer // could keep track of which roots have unhandled errors and call a // forked version of renderRoot. - slowWorkLoopThatChecksForFailedWork(expirationTime); + slowWorkLoopThatChecksForFailedWork(isAsync); return; } - if ( - nextRenderExpirationTime === NoWork || - nextRenderExpirationTime > expirationTime - ) { - return; - } - - if (nextRenderExpirationTime <= mostRecentCurrentTime) { + if (!isAsync) { // Flush all expired work. while (nextUnitOfWork !== null) { nextUnitOfWork = performUnitOfWork(nextUnitOfWork); @@ -11835,15 +11815,8 @@ var ReactFiberScheduler = function(config) { } } - function slowWorkLoopThatChecksForFailedWork(expirationTime) { - if ( - nextRenderExpirationTime === NoWork || - nextRenderExpirationTime > expirationTime - ) { - return; - } - - if (nextRenderExpirationTime <= mostRecentCurrentTime) { + function slowWorkLoopThatChecksForFailedWork(isAsync) { + if (!isAsync) { // Flush all expired work. while (nextUnitOfWork !== null) { if (hasCapturedError(nextUnitOfWork)) { @@ -11866,7 +11839,7 @@ var ReactFiberScheduler = function(config) { } } - function renderRootCatchBlock(root, failedWork, boundary, expirationTime) { + function renderRootCatchBlock(root, failedWork, boundary, isAsync) { // We're going to restart the error boundary that captured the error. // Conceptually, we're unwinding the stack. We need to unwind the // context stack, too. @@ -11880,10 +11853,10 @@ var ReactFiberScheduler = function(config) { nextUnitOfWork = performFailedUnitOfWork(boundary); // Continue working. - workLoop(expirationTime); + workLoop(isAsync); } - function renderRoot(root, expirationTime) { + function renderRoot(root, expirationTime, isAsync) { invariant( !isWorking, "renderRoot was called recursively. This error is likely caused " + @@ -11918,7 +11891,7 @@ var ReactFiberScheduler = function(config) { var didError = false; var error = null; { - invokeGuardedCallback$2(null, workLoop, null, expirationTime); + invokeGuardedCallback$2(null, workLoop, null, isAsync); if (hasCaughtError()) { didError = true; error = clearCaughtError(); @@ -11966,7 +11939,7 @@ var ReactFiberScheduler = function(config) { root, failedWork, boundary, - expirationTime + isAsync ); if (hasCaughtError()) { didError = true; @@ -12247,6 +12220,14 @@ var ReactFiberScheduler = function(config) { return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); } + function computeInteractiveExpiration() { + // Should complete within ~500ms. 600ms max. + var currentTime = recalculateCurrentTime(); + var expirationMs = 500; + var bucketSizeMs = 100; + return computeExpirationBucket(currentTime, expirationMs, bucketSizeMs); + } + // Creates a unique async expiration time. function computeUniqueAsyncExpiration() { var result = computeAsyncExpiration(); @@ -12278,14 +12259,30 @@ var ReactFiberScheduler = function(config) { } else { // No explicit expiration context was set, and we're not currently // performing work. Calculate a new expiration time. - if (fiber.internalContextTag & AsyncUpdates) { - // This is an async update - expirationTime = computeAsyncExpiration(); + if (fiber.mode & AsyncMode) { + if (isBatchingInteractiveUpdates) { + // This is an interactive update + expirationTime = computeInteractiveExpiration(); + } else { + // This is an async update + expirationTime = computeAsyncExpiration(); + } } else { // This is a sync update expirationTime = Sync; } } + if (isBatchingInteractiveUpdates) { + // This is an interactive update. Keep track of the lowest pending + // interactive expiration time. This allows us to synchronously flush + // all interactive updates when needed. + if ( + lowestPendingInteractiveExpirationTime === NoWork || + expirationTime > lowestPendingInteractiveExpirationTime + ) { + lowestPendingInteractiveExpirationTime = expirationTime; + } + } return expirationTime; } @@ -12379,11 +12376,11 @@ var ReactFiberScheduler = function(config) { } } - function syncUpdates(fn) { + function syncUpdates(fn, a, b, c, d) { var previousExpirationContext = expirationContext; expirationContext = Sync; try { - return fn(); + return fn(a, b, c, d); } finally { expirationContext = previousExpirationContext; } @@ -12401,6 +12398,7 @@ var ReactFiberScheduler = function(config) { var isRendering = false; var nextFlushedRoot = null; var nextFlushedExpirationTime = NoWork; + var lowestPendingInteractiveExpirationTime = NoWork; var deadlineDidExpire = false; var hasUnhandledError = false; var unhandledError = null; @@ -12408,6 +12406,7 @@ var ReactFiberScheduler = function(config) { var isBatchingUpdates = false; var isUnbatchingUpdates = false; + var isBatchingInteractiveUpdates = false; var completedBatches = null; @@ -12489,20 +12488,20 @@ var ReactFiberScheduler = function(config) { } if (isBatchingUpdates) { - // Flush work at the end of the batch. if (isUnbatchingUpdates) { + // Flush work at the end of the batch. // ...unless we're inside unbatchedUpdates, in which case we should // flush it now. nextFlushedRoot = root; nextFlushedExpirationTime = Sync; - performWorkOnRoot(root, Sync, recalculateCurrentTime()); + performWorkOnRoot(root, Sync, false); } return; } // TODO: Get rid of Sync and use current time? if (expirationTime === Sync) { - performWork(Sync, null); + performSyncWork(); } else { scheduleCallbackWithExpiration(expirationTime); } @@ -12585,10 +12584,14 @@ var ReactFiberScheduler = function(config) { } function performAsyncWork(dl) { - performWork(NoWork, dl); + performWork(NoWork, true, dl); } - function performWork(minExpirationTime, dl) { + function performSyncWork() { + performWork(Sync, false, null); + } + + function performWork(minExpirationTime, isAsync, dl) { deadline = dl; // Keep working on roots until there's no more work, or until the we reach @@ -12600,20 +12603,32 @@ var ReactFiberScheduler = function(config) { stopRequestCallbackTimer(didExpire); } - while ( - nextFlushedRoot !== null && - nextFlushedExpirationTime !== NoWork && - (minExpirationTime === NoWork || - nextFlushedExpirationTime <= minExpirationTime) && - !deadlineDidExpire - ) { - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - recalculateCurrentTime() - ); - // Find the next highest priority work. - findHighestPriorityRoot(); + if (isAsync) { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime) + ) { + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ); + findHighestPriorityRoot(); + } + } else { + while ( + nextFlushedRoot !== null && + nextFlushedExpirationTime !== NoWork && + (minExpirationTime === NoWork || + minExpirationTime >= nextFlushedExpirationTime) + ) { + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); + findHighestPriorityRoot(); + } } // We're done flushing work. Either we ran out of time in this callback, @@ -12646,7 +12661,7 @@ var ReactFiberScheduler = function(config) { // Perform work on root as if the given expiration time is the current time. // This has the effect of synchronously flushing all work up to and // including the given time. - performWorkOnRoot(root, expirationTime, expirationTime); + performWorkOnRoot(root, expirationTime, false); finishRendering(); } @@ -12675,7 +12690,7 @@ var ReactFiberScheduler = function(config) { } } - function performWorkOnRoot(root, expirationTime, currentTime) { + function performWorkOnRoot(root, expirationTime, isAsync) { invariant( !isRendering, "performWorkOnRoot was called recursively. This error is likely caused " + @@ -12685,7 +12700,7 @@ var ReactFiberScheduler = function(config) { isRendering = true; // Check if this is async work or sync/expired work. - if (expirationTime <= currentTime) { + if (!isAsync) { // Flush sync work. var finishedWork = root.finishedWork; if (finishedWork !== null) { @@ -12693,7 +12708,7 @@ var ReactFiberScheduler = function(config) { completeRoot(root, finishedWork, expirationTime); } else { root.finishedWork = null; - finishedWork = renderRoot(root, expirationTime); + finishedWork = renderRoot(root, expirationTime, false); if (finishedWork !== null) { // We've completed the root. Commit it. completeRoot(root, finishedWork, expirationTime); @@ -12707,7 +12722,7 @@ var ReactFiberScheduler = function(config) { completeRoot(root, _finishedWork, expirationTime); } else { root.finishedWork = null; - _finishedWork = renderRoot(root, expirationTime); + _finishedWork = renderRoot(root, expirationTime, true); if (_finishedWork !== null) { // We've completed the root. Check the deadline one more time // before committing. @@ -12791,40 +12806,93 @@ var ReactFiberScheduler = function(config) { } finally { isBatchingUpdates = previousIsBatchingUpdates; if (!isBatchingUpdates && !isRendering) { - performWork(Sync, null); + performSyncWork(); } } } // TODO: Batching should be implemented at the renderer level, not inside // the reconciler. - function unbatchedUpdates(fn) { + function unbatchedUpdates(fn, a) { if (isBatchingUpdates && !isUnbatchingUpdates) { isUnbatchingUpdates = true; try { - return fn(); + return fn(a); } finally { isUnbatchingUpdates = false; } } - return fn(); + return fn(a); } // TODO: Batching should be implemented at the renderer level, not within // the reconciler. - function flushSync(fn) { + function flushSync(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be " + + "called when React is already rendering." + ); var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = true; try { - return syncUpdates(fn); + return syncUpdates(fn, a); } finally { isBatchingUpdates = previousIsBatchingUpdates; - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be " + - "called when React is already rendering." - ); - performWork(Sync, null); + performSyncWork(); + } + } + + function interactiveUpdates(fn, a, b) { + if (isBatchingInteractiveUpdates) { + return fn(a, b); + } + // If there are any pending interactive updates, synchronously flush them. + // This needs to happen before we read any handlers, because the effect of + // the previous event may influence which handlers are called during + // this event. + if ( + !isBatchingUpdates && + !isRendering && + lowestPendingInteractiveExpirationTime !== NoWork + ) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates; + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingInteractiveUpdates = true; + isBatchingUpdates = true; + try { + return fn(a, b); + } finally { + isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates; + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performSyncWork(); + } + } + } + + function flushInteractiveUpdates() { + if (!isRendering && lowestPendingInteractiveExpirationTime !== NoWork) { + // Synchronously flush pending interactive updates. + performWork(lowestPendingInteractiveExpirationTime, false, null); + lowestPendingInteractiveExpirationTime = NoWork; + } + } + + function flushControlled(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = true; + try { + syncUpdates(fn); + } finally { + isBatchingUpdates = previousIsBatchingUpdates; + if (!isBatchingUpdates && !isRendering) { + performWork(Sync, false, null); + } } } @@ -12836,7 +12904,11 @@ var ReactFiberScheduler = function(config) { batchedUpdates: batchedUpdates, unbatchedUpdates: unbatchedUpdates, flushSync: flushSync, + flushControlled: flushControlled, deferredUpdates: deferredUpdates, + syncUpdates: syncUpdates, + interactiveUpdates: interactiveUpdates, + flushInteractiveUpdates: flushInteractiveUpdates, computeUniqueAsyncExpiration: computeUniqueAsyncExpiration }; }; @@ -12875,7 +12947,11 @@ var ReactFiberReconciler$1 = function(config) { batchedUpdates = _ReactFiberScheduler.batchedUpdates, unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, flushSync = _ReactFiberScheduler.flushSync, - deferredUpdates = _ReactFiberScheduler.deferredUpdates; + flushControlled = _ReactFiberScheduler.flushControlled, + deferredUpdates = _ReactFiberScheduler.deferredUpdates, + syncUpdates = _ReactFiberScheduler.syncUpdates, + interactiveUpdates = _ReactFiberScheduler.interactiveUpdates, + flushInteractiveUpdates = _ReactFiberScheduler.flushInteractiveUpdates; function scheduleRootUpdate(current, element, expirationTime, callback) { { @@ -12990,6 +13066,14 @@ var ReactFiberReconciler$1 = function(config) { deferredUpdates: deferredUpdates, + syncUpdates: syncUpdates, + + interactiveUpdates: interactiveUpdates, + + flushInteractiveUpdates: flushInteractiveUpdates, + + flushControlled: flushControlled, + flushSync: flushSync, getPublicRootInstance: function(container) { @@ -13660,7 +13744,7 @@ function takeSnapshot(view, options) { // Module provided by RN: injectFindHostInstance(NativeRenderer.findHostInstance); -injection$2.injectFiberBatchedUpdates(NativeRenderer.batchedUpdates); +injection$2.injectRenderer(NativeRenderer); var roots = new Map(); diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index 62540b0c5..fa7403bf7 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -1022,27 +1022,29 @@ function restoreStateOfTarget(target) { null.restoreControlledState(target.stateNode, target.type, props); } } -function fiberBatchedUpdates(fn, bookkeeping) { +function _batchedUpdates(fn, bookkeeping) { return fn(bookkeeping); } -var isNestingBatched = !1; +function _flushInteractiveUpdates() {} +var isBatching = !1; function batchedUpdates(fn, bookkeeping) { - if (isNestingBatched) return fiberBatchedUpdates(fn, bookkeeping); - isNestingBatched = !0; + if (isBatching) return fn(bookkeeping); + isBatching = !0; try { - return fiberBatchedUpdates(fn, bookkeeping); + return _batchedUpdates(fn, bookkeeping); } finally { - if ( - ((isNestingBatched = !1), - restoreTarget && - ((bookkeeping = restoreTarget), - (fn = restoreQueue), - (restoreQueue = restoreTarget = null), - restoreStateOfTarget(bookkeeping), - fn)) - ) - for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) - restoreStateOfTarget(fn[bookkeeping]); + if (((isBatching = !1), null !== restoreTarget || null !== restoreQueue)) + if ( + (_flushInteractiveUpdates(), + restoreTarget && + ((bookkeeping = restoreTarget), + (fn = restoreQueue), + (restoreQueue = restoreTarget = null), + restoreStateOfTarget(bookkeeping), + fn)) + ) + for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) + restoreStateOfTarget(fn[bookkeeping]); } } var ReactNativeTagHandles = { @@ -1170,6 +1172,7 @@ var hasSymbol = "function" === typeof Symbol && Symbol["for"], : 60108, REACT_PROVIDER_TYPE = hasSymbol ? Symbol["for"]("react.provider") : 60109, REACT_CONTEXT_TYPE = hasSymbol ? Symbol["for"]("react.context") : 60110, + REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol["for"]("react.async_mode") : 60111, MAYBE_ITERATOR_SYMBOL = "function" === typeof Symbol && Symbol.iterator; function getIteratorFn(maybeIterable) { if (null === maybeIterable || "undefined" === typeof maybeIterable) @@ -1920,7 +1923,7 @@ function invalidateContextProvider(workInProgress, didChange) { } else pop(didPerformWorkStackCursor, workInProgress); push(didPerformWorkStackCursor, didChange, workInProgress); } -function FiberNode(tag, pendingProps, key, internalContextTag) { +function FiberNode(tag, pendingProps, key, mode) { this.tag = tag; this.key = key; this.stateNode = this.type = null; @@ -1929,7 +1932,7 @@ function FiberNode(tag, pendingProps, key, internalContextTag) { this.ref = null; this.pendingProps = pendingProps; this.memoizedState = this.updateQueue = this.memoizedProps = null; - this.internalContextTag = internalContextTag; + this.mode = mode; this.effectTag = 0; this.lastEffect = this.firstEffect = this.nextEffect = null; this.expirationTime = 0; @@ -1942,7 +1945,7 @@ function createWorkInProgress(current, pendingProps, expirationTime) { current.tag, pendingProps, current.key, - current.internalContextTag + current.mode )), (workInProgress.type = current.type), (workInProgress.stateNode = current.stateNode), @@ -1963,7 +1966,7 @@ function createWorkInProgress(current, pendingProps, expirationTime) { workInProgress.ref = current.ref; return workInProgress; } -function createFiberFromElement(element, internalContextTag, expirationTime) { +function createFiberFromElement(element, mode, expirationTime) { var type = element.type, key = element.key; element = element.props; @@ -1976,13 +1979,17 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { case REACT_FRAGMENT_TYPE: return createFiberFromFragment( element.children, - internalContextTag, + mode, expirationTime, key ); + case REACT_ASYNC_MODE_TYPE: + fiberTag = 11; + mode |= 3; + break; case REACT_STRICT_MODE_TYPE: fiberTag = 11; - internalContextTag |= 2; + mode |= 2; break; case REACT_CALL_TYPE: fiberTag = 7; @@ -2002,24 +2009,19 @@ function createFiberFromElement(element, internalContextTag, expirationTime) { default: if ("number" === typeof type.tag) return ( - (internalContextTag = type), - (internalContextTag.pendingProps = element), - (internalContextTag.expirationTime = expirationTime), - internalContextTag + (mode = type), + (mode.pendingProps = element), + (mode.expirationTime = expirationTime), + mode ); throwOnInvalidElementType(type, null); } else throwOnInvalidElementType(type, null); } - internalContextTag = new FiberNode( - fiberTag, - element, - key, - internalContextTag - ); - internalContextTag.type = type; - internalContextTag.expirationTime = expirationTime; - return internalContextTag; + mode = new FiberNode(fiberTag, element, key, mode); + mode.type = type; + mode.expirationTime = expirationTime; + return mode; } function throwOnInvalidElementType(type) { invariant( @@ -2029,35 +2031,30 @@ function throwOnInvalidElementType(type) { "" ); } -function createFiberFromFragment( - elements, - internalContextTag, - expirationTime, - key -) { - elements = new FiberNode(10, elements, key, internalContextTag); +function createFiberFromFragment(elements, mode, expirationTime, key) { + elements = new FiberNode(10, elements, key, mode); elements.expirationTime = expirationTime; return elements; } -function createFiberFromText(content, internalContextTag, expirationTime) { - content = new FiberNode(6, content, null, internalContextTag); +function createFiberFromText(content, mode, expirationTime) { + content = new FiberNode(6, content, null, mode); content.expirationTime = expirationTime; return content; } -function createFiberFromPortal(portal, internalContextTag, expirationTime) { - internalContextTag = new FiberNode( +function createFiberFromPortal(portal, mode, expirationTime) { + mode = new FiberNode( 4, null !== portal.children ? portal.children : [], portal.key, - internalContextTag + mode ); - internalContextTag.expirationTime = expirationTime; - internalContextTag.stateNode = { + mode.expirationTime = expirationTime; + mode.stateNode = { containerInfo: portal.containerInfo, pendingChildren: null, implementation: portal.implementation }; - return internalContextTag; + return mode; } var onCommitFiberRoot = null, onCommitFiberUnmount = null; @@ -2177,7 +2174,7 @@ function processUpdateQueue( null === queue.first && (queue.last = null)); (debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & 2)) && + workInProgress.mode & 2)) && getStateFromUpdate(update, instance, current, props); if (update.isReplace) (current = getStateFromUpdate(update, instance, current, props)), @@ -2247,7 +2244,7 @@ function ReactFiberClassComponent( return ( (debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & 2)) && + workInProgress.mode & 2)) && instance.getDerivedStateFromProps.call( null, props, @@ -2321,7 +2318,7 @@ function ReactFiberClassComponent( : emptyObject; (debugRenderPhaseSideEffects || (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & 2)) && + workInProgress.mode & 2)) && new ctor(props, context); ctor = new ctor(props, context); var state = @@ -2351,18 +2348,14 @@ function ReactFiberClassComponent( instance.state = workInProgress.memoizedState; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); - null != workInProgress.type && - null != workInProgress.type.prototype && - !0 === workInProgress.type.prototype.unstable_isAsyncReactComponent && - ((workInProgress.internalContextTag |= 1), - (workInProgress.internalContextTag |= 2)); ("function" !== typeof instance.UNSAFE_componentWillMount && "function" !== typeof instance.componentWillMount) || "function" === typeof workInProgress.type.getDerivedStateFromProps || ((unmaskedContext = instance.state), - "function" === typeof instance.componentWillMount - ? instance.componentWillMount() - : instance.UNSAFE_componentWillMount(), + "function" === typeof instance.componentWillMount && + instance.componentWillMount(), + "function" === typeof instance.UNSAFE_componentWillMount && + instance.UNSAFE_componentWillMount(), unmaskedContext !== instance.state && updater.enqueueReplaceState(instance, instance.state, null), (unmaskedContext = workInProgress.updateQueue), @@ -2396,12 +2389,13 @@ function ReactFiberClassComponent( "function" === typeof workInProgress.type.getDerivedStateFromProps || (oldProps === newProps && oldContext === newUnmaskedContext) || ((oldContext = instance.state), - "function" === typeof instance.componentWillReceiveProps - ? instance.componentWillReceiveProps(newProps, newUnmaskedContext) - : instance.UNSAFE_componentWillReceiveProps( - newProps, - newUnmaskedContext - ), + "function" === typeof instance.componentWillReceiveProps && + instance.componentWillReceiveProps(newProps, newUnmaskedContext), + "function" === typeof instance.UNSAFE_componentWillReceiveProps && + instance.UNSAFE_componentWillReceiveProps( + newProps, + newUnmaskedContext + ), instance.state !== oldContext && updater.enqueueReplaceState(instance, instance.state, null)); var partialState = void 0; @@ -2472,17 +2466,18 @@ function ReactFiberClassComponent( "function" !== typeof instance.componentWillUpdate) || "function" === typeof workInProgress.type.getDerivedStateFromProps || - ("function" === typeof instance.componentWillUpdate - ? instance.componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - ) - : instance.UNSAFE_componentWillUpdate( - newProps, - renderExpirationTime, - newUnmaskedContext - )), + ("function" === typeof instance.componentWillUpdate && + instance.componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + ), + "function" === typeof instance.UNSAFE_componentWillUpdate && + instance.UNSAFE_componentWillUpdate( + newProps, + renderExpirationTime, + newUnmaskedContext + )), "function" === typeof instance.componentDidUpdate && (workInProgress.effectTag |= 4)) : ("function" !== typeof instance.componentDidUpdate || @@ -2611,7 +2606,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (current = createFiberFromText( textContent, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (current["return"] = returnFiber), @@ -2631,7 +2626,7 @@ function ChildReconciler(shouldTrackSideEffects) { ); expirationTime = createFiberFromElement( element, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); expirationTime.ref = coerceRef(current, element); @@ -2648,7 +2643,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (current = createFiberFromPortal( portal, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (current["return"] = returnFiber), @@ -2663,7 +2658,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (current = createFiberFromFragment( fragment, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, key )), @@ -2679,7 +2674,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (newChild = createFiberFromText( "" + newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (newChild["return"] = returnFiber), @@ -2691,7 +2686,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (expirationTime = createFiberFromElement( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (expirationTime.ref = coerceRef(null, newChild)), @@ -2702,7 +2697,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (newChild = createFiberFromPortal( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (newChild["return"] = returnFiber), @@ -2713,7 +2708,7 @@ function ChildReconciler(shouldTrackSideEffects) { return ( (newChild = createFiberFromFragment( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, null )), @@ -3053,7 +3048,7 @@ function ChildReconciler(shouldTrackSideEffects) { newChild.type === REACT_FRAGMENT_TYPE ? ((currentFirstChild = createFiberFromFragment( newChild.props.children, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime, newChild.key )), @@ -3061,7 +3056,7 @@ function ChildReconciler(shouldTrackSideEffects) { (returnFiber = currentFirstChild)) : ((expirationTime = createFiberFromElement( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime )), (expirationTime.ref = coerceRef(currentFirstChild, newChild)), @@ -3101,7 +3096,7 @@ function ChildReconciler(shouldTrackSideEffects) { } currentFirstChild = createFiberFromPortal( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ); currentFirstChild["return"] = returnFiber; @@ -3122,7 +3117,7 @@ function ChildReconciler(shouldTrackSideEffects) { : (deleteRemainingChildren(returnFiber, currentFirstChild), (currentFirstChild = createFiberFromText( newChild, - returnFiber.internalContextTag, + returnFiber.mode, expirationTime ))), (currentFirstChild["return"] = returnFiber), @@ -3162,6 +3157,13 @@ var reconcileChildFibers = ChildReconciler(!0), mountChildFibers = ChildReconciler(!1), stack = [], index$1 = -1; +function pushProvider(providerFiber) { + index$1 += 1; + stack[index$1] = providerFiber; + var context = providerFiber.type.context; + context.currentValue = providerFiber.pendingProps.value; + context.changedBits = providerFiber.stateNode; +} function popProvider(providerFiber) { stack[index$1] = null; --index$1; @@ -3220,8 +3222,7 @@ function ReactFiberBeginWork( shouldUpdate = workInProgress.stateNode; ReactCurrentOwner.current = workInProgress; (debugRenderPhaseSideEffects || - (debugRenderPhaseSideEffectsForStrictMode && - workInProgress.internalContextTag & 2)) && + (debugRenderPhaseSideEffectsForStrictMode && workInProgress.mode & 2)) && shouldUpdate.render(); var nextChildren = shouldUpdate.render(); workInProgress.effectTag |= 1; @@ -3243,6 +3244,63 @@ function ReactFiberBeginWork( pushTopLevelContextObject(workInProgress, root.context, !1); pushHostContainer(workInProgress, root.containerInfo); } + function propagateContextChange( + workInProgress, + context, + changedBits, + renderExpirationTime + ) { + for (var fiber = workInProgress.child; null !== fiber; ) { + switch (fiber.tag) { + case 12: + var nextFiber = fiber.stateNode | 0; + if (fiber.type === context && 0 !== (nextFiber & changedBits)) { + for (nextFiber = fiber; null !== nextFiber; ) { + var alternate = nextFiber.alternate; + if ( + 0 === nextFiber.expirationTime || + nextFiber.expirationTime > renderExpirationTime + ) + (nextFiber.expirationTime = renderExpirationTime), + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) && + (alternate.expirationTime = renderExpirationTime); + else if ( + null !== alternate && + (0 === alternate.expirationTime || + alternate.expirationTime > renderExpirationTime) + ) + alternate.expirationTime = renderExpirationTime; + else break; + nextFiber = nextFiber["return"]; + } + nextFiber = null; + } else nextFiber = fiber.child; + break; + case 13: + nextFiber = fiber.type === workInProgress.type ? null : fiber.child; + break; + default: + nextFiber = fiber.child; + } + if (null !== nextFiber) nextFiber["return"] = fiber; + else + for (nextFiber = fiber; null !== nextFiber; ) { + if (nextFiber === workInProgress) { + nextFiber = null; + break; + } + fiber = nextFiber.sibling; + if (null !== fiber) { + nextFiber = fiber; + break; + } + nextFiber = nextFiber["return"]; + } + fiber = nextFiber; + } + } function bailoutOnAlreadyFinishedWork(current, workInProgress) { invariant( null === current || workInProgress.child === current.child, @@ -3283,11 +3341,7 @@ function ReactFiberBeginWork( ); break; case 13: - (index$1 += 1), - (stack[index$1] = workInProgress), - (current = workInProgress.type.context), - (current.currentValue = workInProgress.pendingProps.value), - (current.changedBits = workInProgress.stateNode); + pushProvider(workInProgress); } return null; } @@ -3466,7 +3520,7 @@ function ReactFiberBeginWork( (workInProgress.effectTag |= 16), markRef(current, workInProgress), 1073741823 !== renderExpirationTime && - workInProgress.internalContextTag & 1 && + workInProgress.mode & 1 && shouldDeprioritizeSubtree(props, fn) ? ((workInProgress.expirationTime = 1073741823), (current = null)) @@ -3573,9 +3627,66 @@ function ReactFiberBeginWork( current ); case 13: - return null; + props = workInProgress.type.context; + fn = workInProgress.pendingProps; + unmaskedContext = workInProgress.memoizedProps; + if (didPerformWorkStackCursor.current || unmaskedContext !== fn) { + workInProgress.memoizedProps = fn; + memoizedProps = fn.value; + if (null === unmaskedContext) memoizedProps = 1073741823; + else { + var oldValue = unmaskedContext.value; + (oldValue === memoizedProps && + (0 !== oldValue || 1 / oldValue === 1 / memoizedProps)) || + (oldValue !== oldValue && memoizedProps !== memoizedProps) + ? (memoizedProps = 0) + : ((memoizedProps = + "function" === typeof props.calculateChangedBits + ? props.calculateChangedBits(oldValue, memoizedProps) + : 1073741823), + (memoizedProps |= 0), + 0 !== memoizedProps && + propagateContextChange( + workInProgress, + props, + memoizedProps, + renderExpirationTime + )); + } + workInProgress.stateNode = memoizedProps; + pushProvider(workInProgress); + null !== unmaskedContext && unmaskedContext.children === fn.children + ? (current = bailoutOnAlreadyFinishedWork( + current, + workInProgress + )) + : (reconcileChildren(current, workInProgress, fn.children), + (current = workInProgress.child)); + } else + (workInProgress.stateNode = 0), + pushProvider(workInProgress), + (current = bailoutOnAlreadyFinishedWork(current, workInProgress)); + return current; case 12: - return null; + unmaskedContext = workInProgress.type; + fn = workInProgress.pendingProps; + props = unmaskedContext.currentValue; + memoizedProps = unmaskedContext.changedBits; + 0 !== memoizedProps && + propagateContextChange( + workInProgress, + unmaskedContext, + memoizedProps, + renderExpirationTime + ); + renderExpirationTime = fn.observedBits; + if (void 0 === renderExpirationTime || null === renderExpirationTime) + renderExpirationTime = 1073741823; + workInProgress.stateNode = renderExpirationTime; + renderExpirationTime = fn.children; + renderExpirationTime = renderExpirationTime(props); + reconcileChildren(current, workInProgress, renderExpirationTime); + return workInProgress.child; default: invariant( !1, @@ -4508,38 +4619,26 @@ function ReactFiberScheduler(config) { ReactCurrentOwner.current = null; return next; } - function workLoop(expirationTime) { - if (null !== capturedErrors) { - if ( - !( - 0 === nextRenderExpirationTime || - nextRenderExpirationTime > expirationTime - ) - ) - if (nextRenderExpirationTime <= mostRecentCurrentTime) - for (; null !== nextUnitOfWork; ) - nextUnitOfWork = hasCapturedError(nextUnitOfWork) - ? performFailedUnitOfWork(nextUnitOfWork) - : performUnitOfWork(nextUnitOfWork); - else - for (; null !== nextUnitOfWork && !shouldYield(); ) - nextUnitOfWork = hasCapturedError(nextUnitOfWork) - ? performFailedUnitOfWork(nextUnitOfWork) - : performUnitOfWork(nextUnitOfWork); - } else if ( - !( - 0 === nextRenderExpirationTime || - nextRenderExpirationTime > expirationTime - ) - ) - if (nextRenderExpirationTime <= mostRecentCurrentTime) - for (; null !== nextUnitOfWork; ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); - else + function workLoop(isAsync) { + if (null !== capturedErrors) + if (isAsync) for (; null !== nextUnitOfWork && !shouldYield(); ) - nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + nextUnitOfWork = hasCapturedError(nextUnitOfWork) + ? performFailedUnitOfWork(nextUnitOfWork) + : performUnitOfWork(nextUnitOfWork); + else + for (; null !== nextUnitOfWork; ) + nextUnitOfWork = hasCapturedError(nextUnitOfWork) + ? performFailedUnitOfWork(nextUnitOfWork) + : performUnitOfWork(nextUnitOfWork); + else if (isAsync) + for (; null !== nextUnitOfWork && !shouldYield(); ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); + else + for (; null !== nextUnitOfWork; ) + nextUnitOfWork = performUnitOfWork(nextUnitOfWork); } - function renderRoot(root, expirationTime) { + function renderRoot(root, expirationTime, isAsync) { invariant( !isWorking, "renderRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." @@ -4561,6 +4660,7 @@ function ReactFiberScheduler(config) { context.changedBits = 0; stack[i] = null; } + index$1 = -1; resetHostContainer(); nextRoot = root; nextRenderExpirationTime = expirationTime; @@ -4570,65 +4670,69 @@ function ReactFiberScheduler(config) { expirationTime ); } - context = !1; - var error = null; + i = !1; + context = null; try { - workLoop(expirationTime); + workLoop(isAsync); } catch (e) { - (context = !0), (error = e); + (i = !0), (context = e); } - for (; context; ) { + for (; i; ) { if (didFatal) { - firstUncaughtError = error; + firstUncaughtError = context; break; } - i = nextUnitOfWork; - if (null === i) didFatal = !0; + expirationTime = nextUnitOfWork; + if (null === expirationTime) didFatal = !0; else { - var boundary = captureError(i, error); + var boundary = captureError(expirationTime, context); invariant( null !== boundary, "Should have found an error boundary. This error is likely caused by a bug in React. Please file an issue." ); if (!didFatal) { try { - context = boundary; - error = expirationTime; - for (boundary = context; null !== i; ) { - switch (i.tag) { + i = boundary; + context = isAsync; + for (boundary = i; null !== expirationTime; ) { + switch (expirationTime.tag) { case 2: - popContextProvider(i); + popContextProvider(expirationTime); break; case 5: - popHostContext(i); + popHostContext(expirationTime); break; case 3: - popHostContainer(i); + popHostContainer(expirationTime); break; case 4: - popHostContainer(i); + popHostContainer(expirationTime); break; case 13: - popProvider(i); + popProvider(expirationTime); } - if (i === boundary || i.alternate === boundary) break; - i = i["return"]; + if ( + expirationTime === boundary || + expirationTime.alternate === boundary + ) + break; + expirationTime = expirationTime["return"]; } - nextUnitOfWork = performFailedUnitOfWork(context); - workLoop(error); + nextUnitOfWork = performFailedUnitOfWork(i); + workLoop(context); } catch (e) { - context = !0; - error = e; + i = !0; + context = e; continue; } break; } } } - expirationTime = firstUncaughtError; + isAsync = firstUncaughtError; didFatal = isWorking = !1; firstUncaughtError = null; - null !== expirationTime && onUncaughtError(expirationTime); + null !== isAsync && onUncaughtError(isAsync); return root.isReadyForCommit ? root.current.alternate : null; } function captureError(failedWork, error$jscomp$0) { @@ -4762,11 +4866,21 @@ function ReactFiberScheduler(config) { return 20 * ((((recalculateCurrentTime() + 100) / 20) | 0) + 1); } function computeExpirationForFiber(fiber) { - return 0 !== expirationContext - ? expirationContext - : isWorking - ? isCommitting ? 1 : nextRenderExpirationTime - : fiber.internalContextTag & 1 ? computeAsyncExpiration() : 1; + fiber = + 0 !== expirationContext + ? expirationContext + : isWorking + ? isCommitting ? 1 : nextRenderExpirationTime + : fiber.mode & 1 + ? isBatchingInteractiveUpdates + ? 10 * ((((recalculateCurrentTime() + 50) / 10) | 0) + 1) + : computeAsyncExpiration() + : 1; + isBatchingInteractiveUpdates && + (0 === lowestPendingInteractiveExpirationTime || + fiber > lowestPendingInteractiveExpirationTime) && + (lowestPendingInteractiveExpirationTime = fiber); + return fiber; } function scheduleWork(fiber, expirationTime) { return scheduleWorkImpl(fiber, expirationTime, !1); @@ -4803,6 +4917,15 @@ function ReactFiberScheduler(config) { function recalculateCurrentTime() { return (mostRecentCurrentTime = (((now() - startTime) / 10) | 0) + 2); } + function syncUpdates(fn, a, b, c, d) { + var previousExpirationContext = expirationContext; + expirationContext = 1; + try { + return fn(a, b, c, d); + } finally { + expirationContext = previousExpirationContext; + } + } function scheduleCallbackWithExpiration(expirationTime) { if (0 !== callbackExpirationTime) { if (expirationTime > callbackExpirationTime) return; @@ -4840,9 +4963,9 @@ function ReactFiberScheduler(config) { ? isUnbatchingUpdates && ((nextFlushedRoot = root), (nextFlushedExpirationTime = 1), - performWorkOnRoot(root, 1, recalculateCurrentTime())) + performWorkOnRoot(root, 1, !1)) : 1 === expirationTime - ? performWork(1, null) + ? performWork(1, !1, null) : scheduleCallbackWithExpiration(expirationTime)); } function findHighestPriorityRoot() { @@ -4899,25 +5022,39 @@ function ReactFiberScheduler(config) { nextFlushedExpirationTime = highestPriorityWork; } function performAsyncWork(dl) { - performWork(0, dl); + performWork(0, !0, dl); } - function performWork(minExpirationTime, dl) { + function performWork(minExpirationTime, isAsync, dl) { deadline = dl; - for ( - findHighestPriorityRoot(); - null !== nextFlushedRoot && - 0 !== nextFlushedExpirationTime && - (0 === minExpirationTime || - nextFlushedExpirationTime <= minExpirationTime) && - !deadlineDidExpire; + findHighestPriorityRoot(); + if (isAsync) + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime) && + (!deadlineDidExpire || + recalculateCurrentTime() >= nextFlushedExpirationTime); - ) - performWorkOnRoot( - nextFlushedRoot, - nextFlushedExpirationTime, - recalculateCurrentTime() - ), - findHighestPriorityRoot(); + ) + performWorkOnRoot( + nextFlushedRoot, + nextFlushedExpirationTime, + !deadlineDidExpire + ), + findHighestPriorityRoot(); + else + for ( + ; + null !== nextFlushedRoot && + 0 !== nextFlushedExpirationTime && + (0 === minExpirationTime || + minExpirationTime >= nextFlushedExpirationTime); + + ) + performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, !1), + findHighestPriorityRoot(); null !== deadline && ((callbackExpirationTime = 0), (callbackID = -1)); 0 !== nextFlushedExpirationTime && scheduleCallbackWithExpiration(nextFlushedExpirationTime); @@ -4946,29 +5083,28 @@ function ReactFiberScheduler(config) { (hasUnhandledError = !1), batches); } - function performWorkOnRoot(root, expirationTime, currentTime) { + function performWorkOnRoot(root, expirationTime, isAsync) { invariant( !isRendering, "performWorkOnRoot was called recursively. This error is likely caused by a bug in React. Please file an issue." ); isRendering = !0; - expirationTime <= currentTime - ? ((currentTime = root.finishedWork), - null !== currentTime - ? completeRoot(root, currentTime, expirationTime) + isAsync + ? ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) : ((root.finishedWork = null), - (currentTime = renderRoot(root, expirationTime)), - null !== currentTime && - completeRoot(root, currentTime, expirationTime))) - : ((currentTime = root.finishedWork), - null !== currentTime - ? completeRoot(root, currentTime, expirationTime) - : ((root.finishedWork = null), - (currentTime = renderRoot(root, expirationTime)), - null !== currentTime && + (isAsync = renderRoot(root, expirationTime, !0)), + null !== isAsync && (shouldYield() - ? (root.finishedWork = currentTime) - : completeRoot(root, currentTime, expirationTime)))); + ? (root.finishedWork = isAsync) + : completeRoot(root, isAsync, expirationTime)))) + : ((isAsync = root.finishedWork), + null !== isAsync + ? completeRoot(root, isAsync, expirationTime) + : ((root.finishedWork = null), + (isAsync = renderRoot(root, expirationTime, !1)), + null !== isAsync && completeRoot(root, isAsync, expirationTime))); isRendering = !1; } function completeRoot(root, finishedWork, expirationTime) { @@ -5000,7 +5136,7 @@ function ReactFiberScheduler(config) { (firstBatch = finishedWork.firstEffect)) : (firstBatch = finishedWork) : (firstBatch = finishedWork.firstEffect); - prepareForCommit(); + prepareForCommit(expirationTime.containerInfo); for (nextEffect = firstBatch; null !== nextEffect; ) { var didError = !1, _error = void 0; @@ -5043,7 +5179,7 @@ function ReactFiberScheduler(config) { captureError(nextEffect, _error), null !== nextEffect && (nextEffect = nextEffect.nextEffect)); } - resetAfterCommit(); + resetAfterCommit(expirationTime.containerInfo); expirationTime.current = finishedWork; for (nextEffect = firstBatch; null !== nextEffect; ) { effectTag = !1; @@ -5179,12 +5315,14 @@ function ReactFiberScheduler(config) { isRendering = !1, nextFlushedRoot = null, nextFlushedExpirationTime = 0, + lowestPendingInteractiveExpirationTime = 0, deadlineDidExpire = !1, hasUnhandledError = !1, unhandledError = null, deadline = null, isBatchingUpdates = !1, isUnbatchingUpdates = !1, + isBatchingInteractiveUpdates = !1, completedBatches = null, NESTED_UPDATE_LIMIT = 1e3, nestedUpdateCount = 0, @@ -5198,7 +5336,7 @@ function ReactFiberScheduler(config) { !isRendering, "work.commit(): Cannot commit while already rendering. This likely means you attempted to commit from inside a lifecycle method." ); - performWorkOnRoot(root, expirationTime, expirationTime); + performWorkOnRoot(root, expirationTime, !1); finishRendering(); }, batchedUpdates: function(fn, a) { @@ -5209,43 +5347,43 @@ function ReactFiberScheduler(config) { } finally { (isBatchingUpdates = previousIsBatchingUpdates) || isRendering || - performWork(1, null); + performWork(1, !1, null); } }, - unbatchedUpdates: function(fn) { + unbatchedUpdates: function(fn, a) { if (isBatchingUpdates && !isUnbatchingUpdates) { isUnbatchingUpdates = !0; try { - return fn(); + return fn(a); } finally { isUnbatchingUpdates = !1; } } - return fn(); + return fn(a); }, - flushSync: function(fn) { + flushSync: function(fn, a) { + invariant( + !isRendering, + "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." + ); var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = !0; try { - a: { - var previousExpirationContext = expirationContext; - expirationContext = 1; - try { - var JSCompiler_inline_result = fn(); - break a; - } finally { - expirationContext = previousExpirationContext; - } - JSCompiler_inline_result = void 0; - } - return JSCompiler_inline_result; + return syncUpdates(fn, a); } finally { (isBatchingUpdates = previousIsBatchingUpdates), - invariant( - !isRendering, - "flushSync was called from inside a lifecycle method. It cannot be called when React is already rendering." - ), - performWork(1, null); + performWork(1, !1, null); + } + }, + flushControlled: function(fn) { + var previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = !0; + try { + syncUpdates(fn); + } finally { + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performWork(1, !1, null); } }, deferredUpdates: function(fn) { @@ -5257,6 +5395,32 @@ function ReactFiberScheduler(config) { expirationContext = previousExpirationContext; } }, + syncUpdates: syncUpdates, + interactiveUpdates: function(fn, a, b) { + if (isBatchingInteractiveUpdates) return fn(a, b); + isBatchingUpdates || + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + var previousIsBatchingInteractiveUpdates = isBatchingInteractiveUpdates, + previousIsBatchingUpdates = isBatchingUpdates; + isBatchingUpdates = isBatchingInteractiveUpdates = !0; + try { + return fn(a, b); + } finally { + (isBatchingInteractiveUpdates = previousIsBatchingInteractiveUpdates), + (isBatchingUpdates = previousIsBatchingUpdates) || + isRendering || + performWork(1, !1, null); + } + }, + flushInteractiveUpdates: function() { + isRendering || + 0 === lowestPendingInteractiveExpirationTime || + (performWork(lowestPendingInteractiveExpirationTime, !1, null), + (lowestPendingInteractiveExpirationTime = 0)); + }, computeUniqueAsyncExpiration: function() { var result = computeAsyncExpiration(); result <= lastUniqueAsyncExpiration && @@ -5359,6 +5523,10 @@ function ReactFiberReconciler$1(config) { batchedUpdates: config.batchedUpdates, unbatchedUpdates: config.unbatchedUpdates, deferredUpdates: config.deferredUpdates, + syncUpdates: config.syncUpdates, + interactiveUpdates: config.interactiveUpdates, + flushInteractiveUpdates: config.flushInteractiveUpdates, + flushControlled: config.flushControlled, flushSync: config.flushSync, getPublicRootInstance: function(container) { container = container.current; @@ -5693,7 +5861,8 @@ getInspectorDataForViewTag = function() { invariant(!1, "getInspectorDataForViewTag() is not available in production"); }; findHostInstance = NativeRenderer.findHostInstance; -fiberBatchedUpdates = NativeRenderer.batchedUpdates; +_batchedUpdates = NativeRenderer.batchedUpdates; +_flushInteractiveUpdates = NativeRenderer.flushInteractiveUpdates; var roots = new Map(), ReactNativeRenderer = { NativeComponent: ReactNativeComponent, diff --git a/Libraries/Renderer/shims/ReactTypes.js b/Libraries/Renderer/shims/ReactTypes.js index 0e29678f3..9f0dbcff8 100644 --- a/Libraries/Renderer/shims/ReactTypes.js +++ b/Libraries/Renderer/shims/ReactTypes.js @@ -71,19 +71,15 @@ export type ReactConsumer = { key: null | string, ref: null, props: { - render: (value: T) => ReactNodeList, + children: (value: T) => ReactNodeList, bits?: number, }, }; export type ReactContext = { $$typeof: Symbol | number, - provide(value: T, children: ReactNodeList, key?: string): ReactProvider, - consume( - render: (value: T) => ReactNodeList, - observedBits?: number, - key?: string, - ): ReactConsumer, + Consumer: ReactContext, + Provider: ReactProviderType, calculateChangedBits: ((a: T, b: T) => number) | null, defaultValue: T, currentValue: T,