react-test-renderer.mjs (375119B)
1 /** @license React v16.8.6 2 * react-test-renderer.production.min.js 3 * 4 * Copyright (c) Facebook, Inc. and its affiliates. 5 * 6 * This source code is licensed under the MIT license found in the 7 * LICENSE file in the root directory of this source tree. 8 */ 9 import React from 'resource://devtools/client/shared/vendor/react.mjs'; 10 11 /** 12 * Use invariant() to assert state which your program assumes to be true. 13 * 14 * Provide sprintf-style format (only %s is supported) and arguments 15 * to provide information about what broke and what you were 16 * expecting. 17 * 18 * The invariant message will be stripped in production, but the invariant 19 * will remain to ensure logic does not differ in production. 20 */ 21 22 function invariant(condition, format, a, b, c, d, e, f) { 23 if (!condition) { 24 var error = void 0; 25 if (format === undefined) { 26 error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); 27 } else { 28 var args = [a, b, c, d, e, f]; 29 var argIndex = 0; 30 error = new Error(format.replace(/%s/g, function () { 31 return args[argIndex++]; 32 })); 33 error.name = 'Invariant Violation'; 34 } 35 36 error.framesToPop = 1; // we don't care about invariant's own frame 37 throw error; 38 } 39 } 40 41 // Relying on the `invariant()` implementation lets us 42 // preserve the format and params in the www builds. 43 /** 44 * WARNING: DO NOT manually require this module. 45 * This is a replacement for `invariant(...)` used by the error code system 46 * and will _only_ be required by the corresponding babel pass. 47 * It always throws. 48 */ 49 function reactProdInvariant(code) { 50 var argCount = arguments.length - 1; 51 var url = 'https://reactjs.org/docs/error-decoder.html?invariant=' + code; 52 for (var argIdx = 0; argIdx < argCount; argIdx++) { 53 url += '&args[]=' + encodeURIComponent(arguments[argIdx + 1]); 54 } 55 // Rename it so that our build transform doesn't attempt 56 // to replace this invariant() call with reactProdInvariant(). 57 var i = invariant; 58 i(false, 59 // The error code is intentionally part of the message (and 60 // not the format argument) so that we could deduplicate 61 // different errors in logs based on the code. 62 'Minified React error #' + code + '; visit %s ' + 'for the full message or use the non-minified dev environment ' + 'for full errors and additional helpful warnings. ', url); 63 } 64 65 var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 66 67 var _assign = ReactInternals.assign; 68 69 /** 70 * Similar to invariant but only logs a warning if the condition is not met. 71 * This can be used to log issues in development environments in critical 72 * paths. Removing the logging code for production environments will keep the 73 * same logic and follow the same code paths. 74 */ 75 76 /** 77 * `ReactInstanceMap` maintains a mapping from a public facing stateful 78 * instance (key) and the internal representation (value). This allows public 79 * methods to accept the user facing instance as an argument and map them back 80 * to internal methods. 81 * 82 * Note that this module is currently shared and assumed to be stateless. 83 * If this becomes an actual Map, that will break. 84 */ 85 86 /** 87 * This API should be called `delete` but we'd have to make sure to always 88 * transform these to strings for IE support. When this transform is fully 89 * supported we can rename it. 90 */ 91 92 93 function get(key) { 94 return key._reactInternalFiber; 95 } 96 97 98 99 function set(key, value) { 100 key._reactInternalFiber = value; 101 } 102 103 var ReactSharedInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 104 105 // Prevent newer renderers from RTE when used with older react package versions. 106 // Current owner and dispatcher used to share the same ref, 107 // but PR #14548 split them out to better support the react-debug-tools package. 108 if (!ReactSharedInternals.hasOwnProperty('ReactCurrentDispatcher')) { 109 ReactSharedInternals.ReactCurrentDispatcher = { 110 current: null 111 }; 112 } 113 114 // The Symbol used to tag the ReactElement-like types. If there is no native Symbol 115 // nor polyfill, then a plain number is used for performance. 116 var hasSymbol = typeof Symbol === 'function' && Symbol.for; 117 118 var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7; 119 var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca; 120 var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb; 121 var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc; 122 var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2; 123 var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd; 124 var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; 125 126 var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf; 127 var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0; 128 var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1; 129 var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3; 130 var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4; 131 132 var MAYBE_ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 133 var FAUX_ITERATOR_SYMBOL = '@@iterator'; 134 135 function getIteratorFn(maybeIterable) { 136 if (maybeIterable === null || typeof maybeIterable !== 'object') { 137 return null; 138 } 139 var maybeIterator = MAYBE_ITERATOR_SYMBOL && maybeIterable[MAYBE_ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]; 140 if (typeof maybeIterator === 'function') { 141 return maybeIterator; 142 } 143 return null; 144 } 145 146 var Pending = 0; 147 var Resolved = 1; 148 var Rejected = 2; 149 150 function refineResolvedLazyComponent(lazyComponent) { 151 return lazyComponent._status === Resolved ? lazyComponent._result : null; 152 } 153 154 function getWrappedName(outerType, innerType, wrapperName) { 155 var functionName = innerType.displayName || innerType.name || ''; 156 return outerType.displayName || (functionName !== '' ? wrapperName + '(' + functionName + ')' : wrapperName); 157 } 158 159 function getComponentName(type) { 160 if (type == null) { 161 // Host root, text node or just invalid type. 162 return null; 163 } 164 if (typeof type === 'function') { 165 return type.displayName || type.name || null; 166 } 167 if (typeof type === 'string') { 168 return type; 169 } 170 switch (type) { 171 case REACT_CONCURRENT_MODE_TYPE: 172 return 'ConcurrentMode'; 173 case REACT_FRAGMENT_TYPE: 174 return 'Fragment'; 175 case REACT_PORTAL_TYPE: 176 return 'Portal'; 177 case REACT_PROFILER_TYPE: 178 return 'Profiler'; 179 case REACT_STRICT_MODE_TYPE: 180 return 'StrictMode'; 181 case REACT_SUSPENSE_TYPE: 182 return 'Suspense'; 183 } 184 if (typeof type === 'object') { 185 switch (type.$$typeof) { 186 case REACT_CONTEXT_TYPE: 187 return 'Context.Consumer'; 188 case REACT_PROVIDER_TYPE: 189 return 'Context.Provider'; 190 case REACT_FORWARD_REF_TYPE: 191 return getWrappedName(type, type.render, 'ForwardRef'); 192 case REACT_MEMO_TYPE: 193 return getComponentName(type.type); 194 case REACT_LAZY_TYPE: 195 { 196 var thenable = type; 197 var resolvedThenable = refineResolvedLazyComponent(thenable); 198 if (resolvedThenable) { 199 return getComponentName(resolvedThenable); 200 } 201 } 202 } 203 } 204 return null; 205 } 206 207 var FunctionComponent = 0; 208 var ClassComponent = 1; 209 var IndeterminateComponent = 2; // Before we know whether it is function or class 210 var HostRoot = 3; // Root of a host tree. Could be nested inside another node. 211 var HostPortal = 4; // A subtree. Could be an entry point to a different renderer. 212 var HostComponent = 5; 213 var HostText = 6; 214 var Fragment = 7; 215 var Mode = 8; 216 var ContextConsumer = 9; 217 var ContextProvider = 10; 218 var ForwardRef = 11; 219 var Profiler = 12; 220 var SuspenseComponent = 13; 221 var MemoComponent = 14; 222 var SimpleMemoComponent = 15; 223 var LazyComponent = 16; 224 var IncompleteClassComponent = 17; 225 var DehydratedSuspenseComponent = 18; 226 227 // Don't change these two values. They're used by React Dev Tools. 228 var NoEffect = /* */0; 229 var PerformedWork = /* */1; 230 231 // You can change the rest (and add more). 232 var Placement = /* */2; 233 var Update = /* */4; 234 var PlacementAndUpdate = /* */6; 235 var Deletion = /* */8; 236 var ContentReset = /* */16; 237 var Callback = /* */32; 238 var DidCapture = /* */64; 239 var Ref = /* */128; 240 var Snapshot = /* */256; 241 var Passive = /* */512; 242 243 // Passive & Update & Callback & Ref & Snapshot 244 var LifecycleEffectMask = /* */932; 245 246 // Union of all host effects 247 var HostEffectMask = /* */1023; 248 249 var Incomplete = /* */1024; 250 var ShouldCapture = /* */2048; 251 252 var ReactCurrentOwner = ReactSharedInternals.ReactCurrentOwner; 253 254 var MOUNTING = 1; 255 var MOUNTED = 2; 256 var UNMOUNTED = 3; 257 258 function isFiberMountedImpl(fiber) { 259 var node = fiber; 260 if (!fiber.alternate) { 261 // If there is no alternate, this might be a new tree that isn't inserted 262 // yet. If it is, then it will have a pending insertion effect on it. 263 if ((node.effectTag & Placement) !== NoEffect) { 264 return MOUNTING; 265 } 266 while (node.return) { 267 node = node.return; 268 if ((node.effectTag & Placement) !== NoEffect) { 269 return MOUNTING; 270 } 271 } 272 } else { 273 while (node.return) { 274 node = node.return; 275 } 276 } 277 if (node.tag === HostRoot) { 278 // TODO: Check if this was a nested HostRoot when used with 279 // renderContainerIntoSubtree. 280 return MOUNTED; 281 } 282 // If we didn't hit the root, that means that we're in an disconnected tree 283 // that has been unmounted. 284 return UNMOUNTED; 285 } 286 287 function isFiberMounted(fiber) { 288 return isFiberMountedImpl(fiber) === MOUNTED; 289 } 290 291 function isMounted(component) { 292 var fiber = get(component); 293 if (!fiber) { 294 return false; 295 } 296 return isFiberMountedImpl(fiber) === MOUNTED; 297 } 298 299 function assertIsMounted(fiber) { 300 !(isFiberMountedImpl(fiber) === MOUNTED) ? reactProdInvariant('188') : void 0; 301 } 302 303 function findCurrentFiberUsingSlowPath(fiber) { 304 var alternate = fiber.alternate; 305 if (!alternate) { 306 // If there is no alternate, then we only need to check if it is mounted. 307 var state = isFiberMountedImpl(fiber); 308 !(state !== UNMOUNTED) ? reactProdInvariant('188') : void 0; 309 if (state === MOUNTING) { 310 return null; 311 } 312 return fiber; 313 } 314 // If we have two possible branches, we'll walk backwards up to the root 315 // to see what path the root points to. On the way we may hit one of the 316 // special cases and we'll deal with them. 317 var a = fiber; 318 var b = alternate; 319 while (true) { 320 var parentA = a.return; 321 var parentB = parentA ? parentA.alternate : null; 322 if (!parentA || !parentB) { 323 // We're at the root. 324 break; 325 } 326 327 // If both copies of the parent fiber point to the same child, we can 328 // assume that the child is current. This happens when we bailout on low 329 // priority: the bailed out fiber's child reuses the current child. 330 if (parentA.child === parentB.child) { 331 var child = parentA.child; 332 while (child) { 333 if (child === a) { 334 // We've determined that A is the current branch. 335 assertIsMounted(parentA); 336 return fiber; 337 } 338 if (child === b) { 339 // We've determined that B is the current branch. 340 assertIsMounted(parentA); 341 return alternate; 342 } 343 child = child.sibling; 344 } 345 // We should never have an alternate for any mounting node. So the only 346 // way this could possibly happen is if this was unmounted, if at all. 347 reactProdInvariant('188'); 348 } 349 350 if (a.return !== b.return) { 351 // The return pointer of A and the return pointer of B point to different 352 // fibers. We assume that return pointers never criss-cross, so A must 353 // belong to the child set of A.return, and B must belong to the child 354 // set of B.return. 355 a = parentA; 356 b = parentB; 357 } else { 358 // The return pointers point to the same fiber. We'll have to use the 359 // default, slow path: scan the child sets of each parent alternate to see 360 // which child belongs to which set. 361 // 362 // Search parent A's child set 363 var didFindChild = false; 364 var _child = parentA.child; 365 while (_child) { 366 if (_child === a) { 367 didFindChild = true; 368 a = parentA; 369 b = parentB; 370 break; 371 } 372 if (_child === b) { 373 didFindChild = true; 374 b = parentA; 375 a = parentB; 376 break; 377 } 378 _child = _child.sibling; 379 } 380 if (!didFindChild) { 381 // Search parent B's child set 382 _child = parentB.child; 383 while (_child) { 384 if (_child === a) { 385 didFindChild = true; 386 a = parentB; 387 b = parentA; 388 break; 389 } 390 if (_child === b) { 391 didFindChild = true; 392 b = parentB; 393 a = parentA; 394 break; 395 } 396 _child = _child.sibling; 397 } 398 !didFindChild ? reactProdInvariant('189') : void 0; 399 } 400 } 401 402 !(a.alternate === b) ? reactProdInvariant('190') : void 0; 403 } 404 // If the root is not a host container, we're in a disconnected tree. I.e. 405 // unmounted. 406 !(a.tag === HostRoot) ? reactProdInvariant('188') : void 0; 407 if (a.stateNode.current === a) { 408 // We've determined that A is the current branch. 409 return fiber; 410 } 411 // Otherwise B has to be current branch. 412 return alternate; 413 } 414 415 function findCurrentHostFiber(parent) { 416 var currentParent = findCurrentFiberUsingSlowPath(parent); 417 if (!currentParent) { 418 return null; 419 } 420 421 // Next we'll drill down this component to find the first HostComponent/Text. 422 var node = currentParent; 423 while (true) { 424 if (node.tag === HostComponent || node.tag === HostText) { 425 return node; 426 } else if (node.child) { 427 node.child.return = node; 428 node = node.child; 429 continue; 430 } 431 if (node === currentParent) { 432 return null; 433 } 434 while (!node.sibling) { 435 if (!node.return || node.return === currentParent) { 436 return null; 437 } 438 node = node.return; 439 } 440 node.sibling.return = node.return; 441 node = node.sibling; 442 } 443 // Flow needs the return null here, but ESLint complains about it. 444 // eslint-disable-next-line no-unreachable 445 return null; 446 } 447 448 // Current virtual time 449 var nowImplementation = function () { 450 return 0; 451 }; 452 var scheduledCallback = null; 453 var yieldedValues = []; 454 455 var didStop = false; 456 var expectedNumberOfYields = -1; 457 458 function scheduleDeferredCallback$1(callback, options) { 459 scheduledCallback = callback; 460 var fakeCallbackId = 0; 461 return fakeCallbackId; 462 } 463 464 function cancelDeferredCallback$1(timeoutID) { 465 scheduledCallback = null; 466 } 467 468 function setNowImplementation(implementation) { 469 nowImplementation = implementation; 470 } 471 472 function shouldYield$1() { 473 if (expectedNumberOfYields !== -1 && yieldedValues.length >= expectedNumberOfYields) { 474 // We yielded at least as many values as expected. Stop rendering. 475 didStop = true; 476 return true; 477 } 478 // Keep rendering. 479 return false; 480 } 481 482 function flushAll() { 483 yieldedValues = []; 484 while (scheduledCallback !== null) { 485 var cb = scheduledCallback; 486 scheduledCallback = null; 487 cb(); 488 } 489 var values = yieldedValues; 490 yieldedValues = []; 491 return values; 492 } 493 494 function flushNumberOfYields(count) { 495 expectedNumberOfYields = count; 496 didStop = false; 497 yieldedValues = []; 498 try { 499 while (scheduledCallback !== null && !didStop) { 500 var cb = scheduledCallback; 501 scheduledCallback = null; 502 cb(); 503 } 504 return yieldedValues; 505 } finally { 506 expectedNumberOfYields = -1; 507 didStop = false; 508 yieldedValues = []; 509 } 510 } 511 512 function yieldValue(value) { 513 yieldedValues.push(value); 514 } 515 516 function clearYields() { 517 var values = yieldedValues; 518 yieldedValues = []; 519 return values; 520 } 521 522 // Renderers that don't support persistence 523 // can re-export everything from this module. 524 525 function shim() { 526 reactProdInvariant('270'); 527 } 528 529 // Persistence (when unsupported) 530 var supportsPersistence = false; 531 var cloneInstance = shim; 532 var createContainerChildSet = shim; 533 var appendChildToContainerChildSet = shim; 534 var finalizeContainerChildren = shim; 535 var replaceContainerChildren = shim; 536 var cloneHiddenInstance = shim; 537 var cloneUnhiddenInstance = shim; 538 var createHiddenTextInstance = shim; 539 540 // Renderers that don't support hydration 541 // can re-export everything from this module. 542 543 function shim$1() { 544 reactProdInvariant('305'); 545 } 546 547 // Hydration (when unsupported) 548 549 var supportsHydration = false; 550 var canHydrateInstance = shim$1; 551 var canHydrateTextInstance = shim$1; 552 var canHydrateSuspenseInstance = shim$1; 553 var getNextHydratableSibling = shim$1; 554 var getFirstHydratableChild = shim$1; 555 var hydrateInstance = shim$1; 556 var hydrateTextInstance = shim$1; 557 var getNextHydratableInstanceAfterSuspenseInstance = shim$1; 558 var clearSuspenseBoundary = shim$1; 559 var clearSuspenseBoundaryFromContainer = shim$1; 560 561 var NO_CONTEXT = {}; 562 var UPDATE_SIGNAL = {}; 563 function getPublicInstance(inst) { 564 switch (inst.tag) { 565 case 'INSTANCE': 566 var _createNodeMock = inst.rootContainerInstance.createNodeMock; 567 return _createNodeMock({ 568 type: inst.type, 569 props: inst.props 570 }); 571 default: 572 return inst; 573 } 574 } 575 576 function appendChild(parentInstance, child) { 577 var index = parentInstance.children.indexOf(child); 578 if (index !== -1) { 579 parentInstance.children.splice(index, 1); 580 } 581 parentInstance.children.push(child); 582 } 583 584 function insertBefore(parentInstance, child, beforeChild) { 585 var index = parentInstance.children.indexOf(child); 586 if (index !== -1) { 587 parentInstance.children.splice(index, 1); 588 } 589 var beforeIndex = parentInstance.children.indexOf(beforeChild); 590 parentInstance.children.splice(beforeIndex, 0, child); 591 } 592 593 function removeChild(parentInstance, child) { 594 var index = parentInstance.children.indexOf(child); 595 parentInstance.children.splice(index, 1); 596 } 597 598 function getRootHostContext(rootContainerInstance) { 599 return NO_CONTEXT; 600 } 601 602 function getChildHostContext(parentHostContext, type, rootContainerInstance) { 603 return NO_CONTEXT; 604 } 605 606 function prepareForCommit(containerInfo) { 607 // noop 608 } 609 610 function resetAfterCommit(containerInfo) { 611 // noop 612 } 613 614 function createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 615 return { 616 type: type, 617 props: props, 618 isHidden: false, 619 children: [], 620 rootContainerInstance: rootContainerInstance, 621 tag: 'INSTANCE' 622 }; 623 } 624 625 function appendInitialChild(parentInstance, child) { 626 var index = parentInstance.children.indexOf(child); 627 if (index !== -1) { 628 parentInstance.children.splice(index, 1); 629 } 630 parentInstance.children.push(child); 631 } 632 633 function finalizeInitialChildren(testElement, type, props, rootContainerInstance, hostContext) { 634 return false; 635 } 636 637 function prepareUpdate(testElement, type, oldProps, newProps, rootContainerInstance, hostContext) { 638 return UPDATE_SIGNAL; 639 } 640 641 function shouldSetTextContent(type, props) { 642 return false; 643 } 644 645 function shouldDeprioritizeSubtree(type, props) { 646 return false; 647 } 648 649 function createTextInstance(text, rootContainerInstance, hostContext, internalInstanceHandle) { 650 return { 651 text: text, 652 isHidden: false, 653 tag: 'TEXT' 654 }; 655 } 656 657 var isPrimaryRenderer = false; 658 // This approach enables `now` to be mocked by tests, 659 // Even after the reconciler has initialized and read host config values. 660 var now = function () { 661 return nowImplementation(); 662 }; 663 var scheduleDeferredCallback$$1 = scheduleDeferredCallback$1; 664 var cancelDeferredCallback$$1 = cancelDeferredCallback$1; 665 var shouldYield$$1 = shouldYield$1; 666 667 var scheduleTimeout = setTimeout; 668 var cancelTimeout = clearTimeout; 669 var noTimeout = -1; 670 var schedulePassiveEffects = scheduleDeferredCallback$$1; 671 var cancelPassiveEffects = cancelDeferredCallback$$1; 672 673 // ------------------- 674 // Mutation 675 // ------------------- 676 677 var supportsMutation = true; 678 679 function commitUpdate(instance, updatePayload, type, oldProps, newProps, internalInstanceHandle) { 680 instance.type = type; 681 instance.props = newProps; 682 } 683 684 685 686 function commitTextUpdate(textInstance, oldText, newText) { 687 textInstance.text = newText; 688 } 689 690 function resetTextContent(testElement) { 691 // noop 692 } 693 694 var appendChildToContainer = appendChild; 695 var insertInContainerBefore = insertBefore; 696 var removeChildFromContainer = removeChild; 697 698 function hideInstance(instance) { 699 instance.isHidden = true; 700 } 701 702 function hideTextInstance(textInstance) { 703 textInstance.isHidden = true; 704 } 705 706 function unhideInstance(instance, props) { 707 instance.isHidden = false; 708 } 709 710 function unhideTextInstance(textInstance, text) { 711 textInstance.isHidden = false; 712 } 713 714 /** 715 * Copyright (c) 2013-present, Facebook, Inc. 716 * 717 * This source code is licensed under the MIT license found in the 718 * LICENSE file in the root directory of this source tree. 719 */ 720 721 var BEFORE_SLASH_RE = /^(.*)[\\\/]/; 722 723 var describeComponentFrame = function (name, source, ownerName) { 724 var sourceInfo = ''; 725 if (source) { 726 var path = source.fileName; 727 var fileName = path.replace(BEFORE_SLASH_RE, ''); 728 sourceInfo = ' (at ' + fileName + ':' + source.lineNumber + ')'; 729 } else if (ownerName) { 730 sourceInfo = ' (created by ' + ownerName + ')'; 731 } 732 return '\n in ' + (name || 'Unknown') + sourceInfo; 733 }; 734 735 var ReactDebugCurrentFrame = ReactSharedInternals.ReactDebugCurrentFrame; 736 737 function describeFiber(fiber) { 738 switch (fiber.tag) { 739 case HostRoot: 740 case HostPortal: 741 case HostText: 742 case Fragment: 743 case ContextProvider: 744 case ContextConsumer: 745 return ''; 746 default: 747 var owner = fiber._debugOwner; 748 var source = fiber._debugSource; 749 var name = getComponentName(fiber.type); 750 var ownerName = null; 751 if (owner) { 752 ownerName = getComponentName(owner.type); 753 } 754 return describeComponentFrame(name, source, ownerName); 755 } 756 } 757 758 function getStackByFiberInDevAndProd(workInProgress) { 759 var info = ''; 760 var node = workInProgress; 761 do { 762 info += describeFiber(node); 763 node = node.return; 764 } while (node); 765 return info; 766 } 767 768 var enableUserTimingAPI = false; 769 770 771 var enableProfilerTimer = false; 772 var enableSchedulerTracing = false; 773 var enableSuspenseServerRenderer = false; 774 775 776 777 778 779 // Only used in www builds. 780 781 // Prefix measurements so that it's possible to filter them. 782 // Longer prefixes are hard to read in DevTools. 783 var reactEmoji = '\u269B'; 784 var warningEmoji = '\u26D4'; 785 var supportsUserTiming = typeof performance !== 'undefined' && typeof performance.mark === 'function' && typeof performance.clearMarks === 'function' && typeof performance.measure === 'function' && typeof performance.clearMeasures === 'function'; 786 787 // Keep track of current fiber so that we know the path to unwind on pause. 788 // TODO: this looks the same as nextUnitOfWork in scheduler. Can we unify them? 789 var currentFiber = null; 790 // If we're in the middle of user code, which fiber and method is it? 791 // Reusing `currentFiber` would be confusing for this because user code fiber 792 // can change during commit phase too, but we don't need to unwind it (since 793 // lifecycles in the commit phase don't resemble a tree). 794 var currentPhase = null; 795 var currentPhaseFiber = null; 796 // Did lifecycle hook schedule an update? This is often a performance problem, 797 // so we will keep track of it, and include it in the report. 798 // Track commits caused by cascading updates. 799 var isCommitting = false; 800 var hasScheduledUpdateInCurrentCommit = false; 801 var hasScheduledUpdateInCurrentPhase = false; 802 var commitCountInCurrentWorkLoop = 0; 803 var effectCountInCurrentCommit = 0; 804 var isWaitingForCallback = false; 805 // During commits, we only show a measurement once per method name 806 // to avoid stretch the commit phase with measurement overhead. 807 var labelsInCurrentCommit = new Set(); 808 809 var formatMarkName = function (markName) { 810 return reactEmoji + ' ' + markName; 811 }; 812 813 var formatLabel = function (label, warning) { 814 var prefix = warning ? warningEmoji + ' ' : reactEmoji + ' '; 815 var suffix = warning ? ' Warning: ' + warning : ''; 816 return '' + prefix + label + suffix; 817 }; 818 819 var beginMark = function (markName) { 820 performance.mark(formatMarkName(markName)); 821 }; 822 823 var clearMark = function (markName) { 824 performance.clearMarks(formatMarkName(markName)); 825 }; 826 827 var endMark = function (label, markName, warning) { 828 var formattedMarkName = formatMarkName(markName); 829 var formattedLabel = formatLabel(label, warning); 830 try { 831 performance.measure(formattedLabel, formattedMarkName); 832 } catch (err) {} 833 // If previous mark was missing for some reason, this will throw. 834 // This could only happen if React crashed in an unexpected place earlier. 835 // Don't pile on with more errors. 836 837 // Clear marks immediately to avoid growing buffer. 838 performance.clearMarks(formattedMarkName); 839 performance.clearMeasures(formattedLabel); 840 }; 841 842 var getFiberMarkName = function (label, debugID) { 843 return label + ' (#' + debugID + ')'; 844 }; 845 846 var getFiberLabel = function (componentName, isMounted, phase) { 847 if (phase === null) { 848 // These are composite component total time measurements. 849 return componentName + ' [' + (isMounted ? 'update' : 'mount') + ']'; 850 } else { 851 // Composite component methods. 852 return componentName + '.' + phase; 853 } 854 }; 855 856 var beginFiberMark = function (fiber, phase) { 857 var componentName = getComponentName(fiber.type) || 'Unknown'; 858 var debugID = fiber._debugID; 859 var isMounted = fiber.alternate !== null; 860 var label = getFiberLabel(componentName, isMounted, phase); 861 862 if (isCommitting && labelsInCurrentCommit.has(label)) { 863 // During the commit phase, we don't show duplicate labels because 864 // there is a fixed overhead for every measurement, and we don't 865 // want to stretch the commit phase beyond necessary. 866 return false; 867 } 868 labelsInCurrentCommit.add(label); 869 870 var markName = getFiberMarkName(label, debugID); 871 beginMark(markName); 872 return true; 873 }; 874 875 var clearFiberMark = function (fiber, phase) { 876 var componentName = getComponentName(fiber.type) || 'Unknown'; 877 var debugID = fiber._debugID; 878 var isMounted = fiber.alternate !== null; 879 var label = getFiberLabel(componentName, isMounted, phase); 880 var markName = getFiberMarkName(label, debugID); 881 clearMark(markName); 882 }; 883 884 var endFiberMark = function (fiber, phase, warning) { 885 var componentName = getComponentName(fiber.type) || 'Unknown'; 886 var debugID = fiber._debugID; 887 var isMounted = fiber.alternate !== null; 888 var label = getFiberLabel(componentName, isMounted, phase); 889 var markName = getFiberMarkName(label, debugID); 890 endMark(label, markName, warning); 891 }; 892 893 var shouldIgnoreFiber = function (fiber) { 894 // Host components should be skipped in the timeline. 895 // We could check typeof fiber.type, but does this work with RN? 896 switch (fiber.tag) { 897 case HostRoot: 898 case HostComponent: 899 case HostText: 900 case HostPortal: 901 case Fragment: 902 case ContextProvider: 903 case ContextConsumer: 904 case Mode: 905 return true; 906 default: 907 return false; 908 } 909 }; 910 911 var clearPendingPhaseMeasurement = function () { 912 if (currentPhase !== null && currentPhaseFiber !== null) { 913 clearFiberMark(currentPhaseFiber, currentPhase); 914 } 915 currentPhaseFiber = null; 916 currentPhase = null; 917 hasScheduledUpdateInCurrentPhase = false; 918 }; 919 920 var pauseTimers = function () { 921 // Stops all currently active measurements so that they can be resumed 922 // if we continue in a later deferred loop from the same unit of work. 923 var fiber = currentFiber; 924 while (fiber) { 925 if (fiber._debugIsCurrentlyTiming) { 926 endFiberMark(fiber, null, null); 927 } 928 fiber = fiber.return; 929 } 930 }; 931 932 var resumeTimersRecursively = function (fiber) { 933 if (fiber.return !== null) { 934 resumeTimersRecursively(fiber.return); 935 } 936 if (fiber._debugIsCurrentlyTiming) { 937 beginFiberMark(fiber, null); 938 } 939 }; 940 941 var resumeTimers = function () { 942 // Resumes all measurements that were active during the last deferred loop. 943 if (currentFiber !== null) { 944 resumeTimersRecursively(currentFiber); 945 } 946 }; 947 948 function recordEffect() { 949 if (enableUserTimingAPI) { 950 effectCountInCurrentCommit++; 951 } 952 } 953 954 function recordScheduleUpdate() { 955 if (enableUserTimingAPI) { 956 if (isCommitting) { 957 hasScheduledUpdateInCurrentCommit = true; 958 } 959 if (currentPhase !== null && currentPhase !== 'componentWillMount' && currentPhase !== 'componentWillReceiveProps') { 960 hasScheduledUpdateInCurrentPhase = true; 961 } 962 } 963 } 964 965 function startRequestCallbackTimer() { 966 if (enableUserTimingAPI) { 967 if (supportsUserTiming && !isWaitingForCallback) { 968 isWaitingForCallback = true; 969 beginMark('(Waiting for async callback...)'); 970 } 971 } 972 } 973 974 function stopRequestCallbackTimer(didExpire, expirationTime) { 975 if (enableUserTimingAPI) { 976 if (supportsUserTiming) { 977 isWaitingForCallback = false; 978 var warning = didExpire ? 'React was blocked by main thread' : null; 979 endMark('(Waiting for async callback... will force flush in ' + expirationTime + ' ms)', '(Waiting for async callback...)', warning); 980 } 981 } 982 } 983 984 function startWorkTimer(fiber) { 985 if (enableUserTimingAPI) { 986 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 987 return; 988 } 989 // If we pause, this is the fiber to unwind from. 990 currentFiber = fiber; 991 if (!beginFiberMark(fiber, null)) { 992 return; 993 } 994 fiber._debugIsCurrentlyTiming = true; 995 } 996 } 997 998 function cancelWorkTimer(fiber) { 999 if (enableUserTimingAPI) { 1000 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 1001 return; 1002 } 1003 // Remember we shouldn't complete measurement for this fiber. 1004 // Otherwise flamechart will be deep even for small updates. 1005 fiber._debugIsCurrentlyTiming = false; 1006 clearFiberMark(fiber, null); 1007 } 1008 } 1009 1010 function stopWorkTimer(fiber) { 1011 if (enableUserTimingAPI) { 1012 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 1013 return; 1014 } 1015 // If we pause, its parent is the fiber to unwind from. 1016 currentFiber = fiber.return; 1017 if (!fiber._debugIsCurrentlyTiming) { 1018 return; 1019 } 1020 fiber._debugIsCurrentlyTiming = false; 1021 endFiberMark(fiber, null, null); 1022 } 1023 } 1024 1025 function stopFailedWorkTimer(fiber) { 1026 if (enableUserTimingAPI) { 1027 if (!supportsUserTiming || shouldIgnoreFiber(fiber)) { 1028 return; 1029 } 1030 // If we pause, its parent is the fiber to unwind from. 1031 currentFiber = fiber.return; 1032 if (!fiber._debugIsCurrentlyTiming) { 1033 return; 1034 } 1035 fiber._debugIsCurrentlyTiming = false; 1036 var warning = fiber.tag === SuspenseComponent || fiber.tag === DehydratedSuspenseComponent ? 'Rendering was suspended' : 'An error was thrown inside this error boundary'; 1037 endFiberMark(fiber, null, warning); 1038 } 1039 } 1040 1041 function startPhaseTimer(fiber, phase) { 1042 if (enableUserTimingAPI) { 1043 if (!supportsUserTiming) { 1044 return; 1045 } 1046 clearPendingPhaseMeasurement(); 1047 if (!beginFiberMark(fiber, phase)) { 1048 return; 1049 } 1050 currentPhaseFiber = fiber; 1051 currentPhase = phase; 1052 } 1053 } 1054 1055 function stopPhaseTimer() { 1056 if (enableUserTimingAPI) { 1057 if (!supportsUserTiming) { 1058 return; 1059 } 1060 if (currentPhase !== null && currentPhaseFiber !== null) { 1061 var warning = hasScheduledUpdateInCurrentPhase ? 'Scheduled a cascading update' : null; 1062 endFiberMark(currentPhaseFiber, currentPhase, warning); 1063 } 1064 currentPhase = null; 1065 currentPhaseFiber = null; 1066 } 1067 } 1068 1069 function startWorkLoopTimer(nextUnitOfWork) { 1070 if (enableUserTimingAPI) { 1071 currentFiber = nextUnitOfWork; 1072 if (!supportsUserTiming) { 1073 return; 1074 } 1075 commitCountInCurrentWorkLoop = 0; 1076 // This is top level call. 1077 // Any other measurements are performed within. 1078 beginMark('(React Tree Reconciliation)'); 1079 // Resume any measurements that were in progress during the last loop. 1080 resumeTimers(); 1081 } 1082 } 1083 1084 function stopWorkLoopTimer(interruptedBy, didCompleteRoot) { 1085 if (enableUserTimingAPI) { 1086 if (!supportsUserTiming) { 1087 return; 1088 } 1089 var warning = null; 1090 if (interruptedBy !== null) { 1091 if (interruptedBy.tag === HostRoot) { 1092 warning = 'A top-level update interrupted the previous render'; 1093 } else { 1094 var componentName = getComponentName(interruptedBy.type) || 'Unknown'; 1095 warning = 'An update to ' + componentName + ' interrupted the previous render'; 1096 } 1097 } else if (commitCountInCurrentWorkLoop > 1) { 1098 warning = 'There were cascading updates'; 1099 } 1100 commitCountInCurrentWorkLoop = 0; 1101 var label = didCompleteRoot ? '(React Tree Reconciliation: Completed Root)' : '(React Tree Reconciliation: Yielded)'; 1102 // Pause any measurements until the next loop. 1103 pauseTimers(); 1104 endMark(label, '(React Tree Reconciliation)', warning); 1105 } 1106 } 1107 1108 function startCommitTimer() { 1109 if (enableUserTimingAPI) { 1110 if (!supportsUserTiming) { 1111 return; 1112 } 1113 isCommitting = true; 1114 hasScheduledUpdateInCurrentCommit = false; 1115 labelsInCurrentCommit.clear(); 1116 beginMark('(Committing Changes)'); 1117 } 1118 } 1119 1120 function stopCommitTimer() { 1121 if (enableUserTimingAPI) { 1122 if (!supportsUserTiming) { 1123 return; 1124 } 1125 1126 var warning = null; 1127 if (hasScheduledUpdateInCurrentCommit) { 1128 warning = 'Lifecycle hook scheduled a cascading update'; 1129 } else if (commitCountInCurrentWorkLoop > 0) { 1130 warning = 'Caused by a cascading update in earlier commit'; 1131 } 1132 hasScheduledUpdateInCurrentCommit = false; 1133 commitCountInCurrentWorkLoop++; 1134 isCommitting = false; 1135 labelsInCurrentCommit.clear(); 1136 1137 endMark('(Committing Changes)', '(Committing Changes)', warning); 1138 } 1139 } 1140 1141 function startCommitSnapshotEffectsTimer() { 1142 if (enableUserTimingAPI) { 1143 if (!supportsUserTiming) { 1144 return; 1145 } 1146 effectCountInCurrentCommit = 0; 1147 beginMark('(Committing Snapshot Effects)'); 1148 } 1149 } 1150 1151 function stopCommitSnapshotEffectsTimer() { 1152 if (enableUserTimingAPI) { 1153 if (!supportsUserTiming) { 1154 return; 1155 } 1156 var count = effectCountInCurrentCommit; 1157 effectCountInCurrentCommit = 0; 1158 endMark('(Committing Snapshot Effects: ' + count + ' Total)', '(Committing Snapshot Effects)', null); 1159 } 1160 } 1161 1162 function startCommitHostEffectsTimer() { 1163 if (enableUserTimingAPI) { 1164 if (!supportsUserTiming) { 1165 return; 1166 } 1167 effectCountInCurrentCommit = 0; 1168 beginMark('(Committing Host Effects)'); 1169 } 1170 } 1171 1172 function stopCommitHostEffectsTimer() { 1173 if (enableUserTimingAPI) { 1174 if (!supportsUserTiming) { 1175 return; 1176 } 1177 var count = effectCountInCurrentCommit; 1178 effectCountInCurrentCommit = 0; 1179 endMark('(Committing Host Effects: ' + count + ' Total)', '(Committing Host Effects)', null); 1180 } 1181 } 1182 1183 function startCommitLifeCyclesTimer() { 1184 if (enableUserTimingAPI) { 1185 if (!supportsUserTiming) { 1186 return; 1187 } 1188 effectCountInCurrentCommit = 0; 1189 beginMark('(Calling Lifecycle Methods)'); 1190 } 1191 } 1192 1193 function stopCommitLifeCyclesTimer() { 1194 if (enableUserTimingAPI) { 1195 if (!supportsUserTiming) { 1196 return; 1197 } 1198 var count = effectCountInCurrentCommit; 1199 effectCountInCurrentCommit = 0; 1200 endMark('(Calling Lifecycle Methods: ' + count + ' Total)', '(Calling Lifecycle Methods)', null); 1201 } 1202 } 1203 1204 var valueStack = []; 1205 1206 var index = -1; 1207 1208 function createCursor(defaultValue) { 1209 return { 1210 current: defaultValue 1211 }; 1212 } 1213 1214 function pop(cursor, fiber) { 1215 if (index < 0) { 1216 return; 1217 } 1218 1219 cursor.current = valueStack[index]; 1220 1221 valueStack[index] = null; 1222 1223 index--; 1224 } 1225 1226 function push(cursor, value, fiber) { 1227 index++; 1228 1229 valueStack[index] = cursor.current; 1230 1231 cursor.current = value; 1232 } 1233 1234 var emptyContextObject = {}; 1235 // A cursor to the current merged context object on the stack. 1236 var contextStackCursor = createCursor(emptyContextObject); 1237 // A cursor to a boolean indicating whether the context has changed. 1238 var didPerformWorkStackCursor = createCursor(false); 1239 // Keep track of the previous context object that was on the stack. 1240 // We use this to get access to the parent context after we have already 1241 // pushed the next context provider, and now need to merge their contexts. 1242 var previousContext = emptyContextObject; 1243 1244 function getUnmaskedContext(workInProgress, Component, didPushOwnContextIfProvider) { 1245 if (didPushOwnContextIfProvider && isContextProvider(Component)) { 1246 // If the fiber is a context provider itself, when we read its context 1247 // we may have already pushed its own child context on the stack. A context 1248 // provider should not "see" its own child context. Therefore we read the 1249 // previous (parent) context instead for a context provider. 1250 return previousContext; 1251 } 1252 return contextStackCursor.current; 1253 } 1254 1255 function cacheContext(workInProgress, unmaskedContext, maskedContext) { 1256 var instance = workInProgress.stateNode; 1257 instance.__reactInternalMemoizedUnmaskedChildContext = unmaskedContext; 1258 instance.__reactInternalMemoizedMaskedChildContext = maskedContext; 1259 } 1260 1261 function getMaskedContext(workInProgress, unmaskedContext) { 1262 var type = workInProgress.type; 1263 var contextTypes = type.contextTypes; 1264 if (!contextTypes) { 1265 return emptyContextObject; 1266 } 1267 1268 // Avoid recreating masked context unless unmasked context has changed. 1269 // Failing to do this will result in unnecessary calls to componentWillReceiveProps. 1270 // This may trigger infinite loops if componentWillReceiveProps calls setState. 1271 var instance = workInProgress.stateNode; 1272 if (instance && instance.__reactInternalMemoizedUnmaskedChildContext === unmaskedContext) { 1273 return instance.__reactInternalMemoizedMaskedChildContext; 1274 } 1275 1276 var context = {}; 1277 for (var key in contextTypes) { 1278 context[key] = unmaskedContext[key]; 1279 } 1280 1281 if (instance) { 1282 cacheContext(workInProgress, unmaskedContext, context); 1283 } 1284 1285 return context; 1286 } 1287 1288 function hasContextChanged() { 1289 return didPerformWorkStackCursor.current; 1290 } 1291 1292 function isContextProvider(type) { 1293 var childContextTypes = type.childContextTypes; 1294 return childContextTypes !== null && childContextTypes !== undefined; 1295 } 1296 1297 function popContext(fiber) { 1298 pop(didPerformWorkStackCursor, fiber); 1299 pop(contextStackCursor, fiber); 1300 } 1301 1302 function popTopLevelContextObject(fiber) { 1303 pop(didPerformWorkStackCursor, fiber); 1304 pop(contextStackCursor, fiber); 1305 } 1306 1307 function pushTopLevelContextObject(fiber, context, didChange) { 1308 !(contextStackCursor.current === emptyContextObject) ? reactProdInvariant('168') : void 0; 1309 1310 push(contextStackCursor, context, fiber); 1311 push(didPerformWorkStackCursor, didChange, fiber); 1312 } 1313 1314 function processChildContext(fiber, type, parentContext) { 1315 var instance = fiber.stateNode; 1316 var childContextTypes = type.childContextTypes; 1317 1318 // TODO (bvaughn) Replace this behavior with an invariant() in the future. 1319 // It has only been added in Fiber to match the (unintentional) behavior in Stack. 1320 if (typeof instance.getChildContext !== 'function') { 1321 return parentContext; 1322 } 1323 1324 var childContext = void 0; 1325 startPhaseTimer(fiber, 'getChildContext'); 1326 childContext = instance.getChildContext(); 1327 stopPhaseTimer(); 1328 for (var contextKey in childContext) { 1329 !(contextKey in childContextTypes) ? reactProdInvariant('108', getComponentName(type) || 'Unknown', contextKey) : void 0; 1330 } 1331 return _assign({}, parentContext, childContext); 1332 } 1333 1334 function pushContextProvider(workInProgress) { 1335 var instance = workInProgress.stateNode; 1336 // We push the context as early as possible to ensure stack integrity. 1337 // If the instance does not exist yet, we will push null at first, 1338 // and replace it on the stack later when invalidating the context. 1339 var memoizedMergedChildContext = instance && instance.__reactInternalMemoizedMergedChildContext || emptyContextObject; 1340 1341 // Remember the parent context so we can merge with it later. 1342 // Inherit the parent's did-perform-work value to avoid inadvertently blocking updates. 1343 previousContext = contextStackCursor.current; 1344 push(contextStackCursor, memoizedMergedChildContext, workInProgress); 1345 push(didPerformWorkStackCursor, didPerformWorkStackCursor.current, workInProgress); 1346 1347 return true; 1348 } 1349 1350 function invalidateContextProvider(workInProgress, type, didChange) { 1351 var instance = workInProgress.stateNode; 1352 !instance ? reactProdInvariant('169') : void 0; 1353 1354 if (didChange) { 1355 // Merge parent and own context. 1356 // Skip this if we're not updating due to sCU. 1357 // This avoids unnecessarily recomputing memoized values. 1358 var mergedContext = processChildContext(workInProgress, type, previousContext); 1359 instance.__reactInternalMemoizedMergedChildContext = mergedContext; 1360 1361 // Replace the old (or empty) context with the new one. 1362 // It is important to unwind the context in the reverse order. 1363 pop(didPerformWorkStackCursor, workInProgress); 1364 pop(contextStackCursor, workInProgress); 1365 // Now push the new context and mark that it has changed. 1366 push(contextStackCursor, mergedContext, workInProgress); 1367 push(didPerformWorkStackCursor, didChange, workInProgress); 1368 } else { 1369 pop(didPerformWorkStackCursor, workInProgress); 1370 push(didPerformWorkStackCursor, didChange, workInProgress); 1371 } 1372 } 1373 1374 function findCurrentUnmaskedContext(fiber) { 1375 // Currently this is only used with renderSubtreeIntoContainer; not sure if it 1376 // makes sense elsewhere 1377 !(isFiberMounted(fiber) && fiber.tag === ClassComponent) ? reactProdInvariant('170') : void 0; 1378 1379 var node = fiber; 1380 do { 1381 switch (node.tag) { 1382 case HostRoot: 1383 return node.stateNode.context; 1384 case ClassComponent: 1385 { 1386 var Component = node.type; 1387 if (isContextProvider(Component)) { 1388 return node.stateNode.__reactInternalMemoizedMergedChildContext; 1389 } 1390 break; 1391 } 1392 } 1393 node = node.return; 1394 } while (node !== null); 1395 reactProdInvariant('171'); 1396 } 1397 1398 var onCommitFiberRoot = null; 1399 var onCommitFiberUnmount = null; 1400 function catchErrors(fn) { 1401 return function (arg) { 1402 try { 1403 return fn(arg); 1404 } catch (err) { 1405 1406 } 1407 }; 1408 } 1409 1410 var isDevToolsPresent = typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined'; 1411 1412 function injectInternals(internals) { 1413 if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { 1414 // No DevTools 1415 return false; 1416 } 1417 var hook = __REACT_DEVTOOLS_GLOBAL_HOOK__; 1418 if (hook.isDisabled) { 1419 // This isn't a real property on the hook, but it can be set to opt out 1420 // of DevTools integration and associated warnings and logs. 1421 // https://github.com/facebook/react/issues/3877 1422 return true; 1423 } 1424 if (!hook.supportsFiber) { 1425 return true; 1426 } 1427 try { 1428 var rendererID = hook.inject(internals); 1429 // We have successfully injected, so now it is safe to set up hooks. 1430 onCommitFiberRoot = catchErrors(function (root) { 1431 return hook.onCommitFiberRoot(rendererID, root); 1432 }); 1433 onCommitFiberUnmount = catchErrors(function (fiber) { 1434 return hook.onCommitFiberUnmount(rendererID, fiber); 1435 }); 1436 } catch (err) { 1437 // Catch all errors because it is unsafe to throw during initialization. 1438 1439 } 1440 // DevTools exists 1441 return true; 1442 } 1443 1444 function onCommitRoot(root) { 1445 if (typeof onCommitFiberRoot === 'function') { 1446 onCommitFiberRoot(root); 1447 } 1448 } 1449 1450 function onCommitUnmount(fiber) { 1451 if (typeof onCommitFiberUnmount === 'function') { 1452 onCommitFiberUnmount(fiber); 1453 } 1454 } 1455 1456 // Max 31 bit integer. The max integer size in V8 for 32-bit systems. 1457 // Math.pow(2, 30) - 1 1458 // 0b111111111111111111111111111111 1459 var maxSigned31BitInt = 1073741823; 1460 1461 var NoWork = 0; 1462 var Never = 1; 1463 var Sync = maxSigned31BitInt; 1464 1465 var UNIT_SIZE = 10; 1466 var MAGIC_NUMBER_OFFSET = maxSigned31BitInt - 1; 1467 1468 // 1 unit of expiration time represents 10ms. 1469 function msToExpirationTime(ms) { 1470 // Always add an offset so that we don't clash with the magic number for NoWork. 1471 return MAGIC_NUMBER_OFFSET - (ms / UNIT_SIZE | 0); 1472 } 1473 1474 function expirationTimeToMs(expirationTime) { 1475 return (MAGIC_NUMBER_OFFSET - expirationTime) * UNIT_SIZE; 1476 } 1477 1478 function ceiling(num, precision) { 1479 return ((num / precision | 0) + 1) * precision; 1480 } 1481 1482 function computeExpirationBucket(currentTime, expirationInMs, bucketSizeMs) { 1483 return MAGIC_NUMBER_OFFSET - ceiling(MAGIC_NUMBER_OFFSET - currentTime + expirationInMs / UNIT_SIZE, bucketSizeMs / UNIT_SIZE); 1484 } 1485 1486 var LOW_PRIORITY_EXPIRATION = 5000; 1487 var LOW_PRIORITY_BATCH_SIZE = 250; 1488 1489 function computeAsyncExpiration(currentTime) { 1490 return computeExpirationBucket(currentTime, LOW_PRIORITY_EXPIRATION, LOW_PRIORITY_BATCH_SIZE); 1491 } 1492 1493 // We intentionally set a higher expiration time for interactive updates in 1494 // dev than in production. 1495 // 1496 // If the main thread is being blocked so long that you hit the expiration, 1497 // it's a problem that could be solved with better scheduling. 1498 // 1499 // People will be more likely to notice this and fix it with the long 1500 // expiration time in development. 1501 // 1502 // In production we opt for better UX at the risk of masking scheduling 1503 // problems, by expiring fast. 1504 var HIGH_PRIORITY_EXPIRATION = 150; 1505 var HIGH_PRIORITY_BATCH_SIZE = 100; 1506 1507 function computeInteractiveExpiration(currentTime) { 1508 return computeExpirationBucket(currentTime, HIGH_PRIORITY_EXPIRATION, HIGH_PRIORITY_BATCH_SIZE); 1509 } 1510 1511 var NoContext = 0; 1512 var ConcurrentMode = 1; 1513 var StrictMode = 2; 1514 var ProfileMode = 4; 1515 1516 function FiberNode(tag, pendingProps, key, mode) { 1517 // Instance 1518 this.tag = tag; 1519 this.key = key; 1520 this.elementType = null; 1521 this.type = null; 1522 this.stateNode = null; 1523 1524 // Fiber 1525 this.return = null; 1526 this.child = null; 1527 this.sibling = null; 1528 this.index = 0; 1529 1530 this.ref = null; 1531 1532 this.pendingProps = pendingProps; 1533 this.memoizedProps = null; 1534 this.updateQueue = null; 1535 this.memoizedState = null; 1536 this.contextDependencies = null; 1537 1538 this.mode = mode; 1539 1540 // Effects 1541 this.effectTag = NoEffect; 1542 this.nextEffect = null; 1543 1544 this.firstEffect = null; 1545 this.lastEffect = null; 1546 1547 this.expirationTime = NoWork; 1548 this.childExpirationTime = NoWork; 1549 1550 this.alternate = null; 1551 1552 if (enableProfilerTimer) { 1553 // Note: The following is done to avoid a v8 performance cliff. 1554 // 1555 // Initializing the fields below to smis and later updating them with 1556 // double values will cause Fibers to end up having separate shapes. 1557 // This behavior/bug has something to do with Object.preventExtension(). 1558 // Fortunately this only impacts DEV builds. 1559 // Unfortunately it makes React unusably slow for some applications. 1560 // To work around this, initialize the fields below with doubles. 1561 // 1562 // Learn more about this here: 1563 // https://github.com/facebook/react/issues/14365 1564 // https://bugs.chromium.org/p/v8/issues/detail?id=8538 1565 this.actualDuration = Number.NaN; 1566 this.actualStartTime = Number.NaN; 1567 this.selfBaseDuration = Number.NaN; 1568 this.treeBaseDuration = Number.NaN; 1569 1570 // It's okay to replace the initial doubles with smis after initialization. 1571 // This won't trigger the performance cliff mentioned above, 1572 // and it simplifies other profiler code (including DevTools). 1573 this.actualDuration = 0; 1574 this.actualStartTime = -1; 1575 this.selfBaseDuration = 0; 1576 this.treeBaseDuration = 0; 1577 } 1578 1579 1580 } 1581 1582 // This is a constructor function, rather than a POJO constructor, still 1583 // please ensure we do the following: 1584 // 1) Nobody should add any instance methods on this. Instance methods can be 1585 // more difficult to predict when they get optimized and they are almost 1586 // never inlined properly in static compilers. 1587 // 2) Nobody should rely on `instanceof Fiber` for type testing. We should 1588 // always know when it is a fiber. 1589 // 3) We might want to experiment with using numeric keys since they are easier 1590 // to optimize in a non-JIT environment. 1591 // 4) We can easily go from a constructor to a createFiber object literal if that 1592 // is faster. 1593 // 5) It should be easy to port this to a C struct and keep a C implementation 1594 // compatible. 1595 var createFiber = function (tag, pendingProps, key, mode) { 1596 // $FlowFixMe: the shapes are exact here but Flow doesn't like constructors 1597 return new FiberNode(tag, pendingProps, key, mode); 1598 }; 1599 1600 function shouldConstruct(Component) { 1601 var prototype = Component.prototype; 1602 return !!(prototype && prototype.isReactComponent); 1603 } 1604 1605 function isSimpleFunctionComponent(type) { 1606 return typeof type === 'function' && !shouldConstruct(type) && type.defaultProps === undefined; 1607 } 1608 1609 function resolveLazyComponentTag(Component) { 1610 if (typeof Component === 'function') { 1611 return shouldConstruct(Component) ? ClassComponent : FunctionComponent; 1612 } else if (Component !== undefined && Component !== null) { 1613 var $$typeof = Component.$$typeof; 1614 if ($$typeof === REACT_FORWARD_REF_TYPE) { 1615 return ForwardRef; 1616 } 1617 if ($$typeof === REACT_MEMO_TYPE) { 1618 return MemoComponent; 1619 } 1620 } 1621 return IndeterminateComponent; 1622 } 1623 1624 // This is used to create an alternate fiber to do work on. 1625 function createWorkInProgress(current, pendingProps, expirationTime) { 1626 var workInProgress = current.alternate; 1627 if (workInProgress === null) { 1628 // We use a double buffering pooling technique because we know that we'll 1629 // only ever need at most two versions of a tree. We pool the "other" unused 1630 // node that we're free to reuse. This is lazily created to avoid allocating 1631 // extra objects for things that are never updated. It also allow us to 1632 // reclaim the extra memory if needed. 1633 workInProgress = createFiber(current.tag, pendingProps, current.key, current.mode); 1634 workInProgress.elementType = current.elementType; 1635 workInProgress.type = current.type; 1636 workInProgress.stateNode = current.stateNode; 1637 1638 workInProgress.alternate = current; 1639 current.alternate = workInProgress; 1640 } else { 1641 workInProgress.pendingProps = pendingProps; 1642 1643 // We already have an alternate. 1644 // Reset the effect tag. 1645 workInProgress.effectTag = NoEffect; 1646 1647 // The effect list is no longer valid. 1648 workInProgress.nextEffect = null; 1649 workInProgress.firstEffect = null; 1650 workInProgress.lastEffect = null; 1651 1652 if (enableProfilerTimer) { 1653 // We intentionally reset, rather than copy, actualDuration & actualStartTime. 1654 // This prevents time from endlessly accumulating in new commits. 1655 // This has the downside of resetting values for different priority renders, 1656 // But works for yielding (the common case) and should support resuming. 1657 workInProgress.actualDuration = 0; 1658 workInProgress.actualStartTime = -1; 1659 } 1660 } 1661 1662 workInProgress.childExpirationTime = current.childExpirationTime; 1663 workInProgress.expirationTime = current.expirationTime; 1664 1665 workInProgress.child = current.child; 1666 workInProgress.memoizedProps = current.memoizedProps; 1667 workInProgress.memoizedState = current.memoizedState; 1668 workInProgress.updateQueue = current.updateQueue; 1669 workInProgress.contextDependencies = current.contextDependencies; 1670 1671 // These will be overridden during the parent's reconciliation 1672 workInProgress.sibling = current.sibling; 1673 workInProgress.index = current.index; 1674 workInProgress.ref = current.ref; 1675 1676 if (enableProfilerTimer) { 1677 workInProgress.selfBaseDuration = current.selfBaseDuration; 1678 workInProgress.treeBaseDuration = current.treeBaseDuration; 1679 } 1680 1681 return workInProgress; 1682 } 1683 1684 function createHostRootFiber(isConcurrent) { 1685 var mode = isConcurrent ? ConcurrentMode | StrictMode : NoContext; 1686 1687 if (enableProfilerTimer && isDevToolsPresent) { 1688 // Always collect profile timings when DevTools are present. 1689 // This enables DevTools to start capturing timing at any point– 1690 // Without some nodes in the tree having empty base times. 1691 mode |= ProfileMode; 1692 } 1693 1694 return createFiber(HostRoot, null, null, mode); 1695 } 1696 1697 function createFiberFromTypeAndProps(type, // React$ElementType 1698 key, pendingProps, owner, mode, expirationTime) { 1699 var fiber = void 0; 1700 1701 var fiberTag = IndeterminateComponent; 1702 // The resolved type is set if we know what the final type will be. I.e. it's not lazy. 1703 var resolvedType = type; 1704 if (typeof type === 'function') { 1705 if (shouldConstruct(type)) { 1706 fiberTag = ClassComponent; 1707 } 1708 } else if (typeof type === 'string') { 1709 fiberTag = HostComponent; 1710 } else { 1711 getTag: switch (type) { 1712 case REACT_FRAGMENT_TYPE: 1713 return createFiberFromFragment(pendingProps.children, mode, expirationTime, key); 1714 case REACT_CONCURRENT_MODE_TYPE: 1715 return createFiberFromMode(pendingProps, mode | ConcurrentMode | StrictMode, expirationTime, key); 1716 case REACT_STRICT_MODE_TYPE: 1717 return createFiberFromMode(pendingProps, mode | StrictMode, expirationTime, key); 1718 case REACT_PROFILER_TYPE: 1719 return createFiberFromProfiler(pendingProps, mode, expirationTime, key); 1720 case REACT_SUSPENSE_TYPE: 1721 return createFiberFromSuspense(pendingProps, mode, expirationTime, key); 1722 default: 1723 { 1724 if (typeof type === 'object' && type !== null) { 1725 switch (type.$$typeof) { 1726 case REACT_PROVIDER_TYPE: 1727 fiberTag = ContextProvider; 1728 break getTag; 1729 case REACT_CONTEXT_TYPE: 1730 // This is a consumer 1731 fiberTag = ContextConsumer; 1732 break getTag; 1733 case REACT_FORWARD_REF_TYPE: 1734 fiberTag = ForwardRef; 1735 break getTag; 1736 case REACT_MEMO_TYPE: 1737 fiberTag = MemoComponent; 1738 break getTag; 1739 case REACT_LAZY_TYPE: 1740 fiberTag = LazyComponent; 1741 resolvedType = null; 1742 break getTag; 1743 } 1744 } 1745 var info = ''; 1746 reactProdInvariant('130', type == null ? type : typeof type, info); 1747 } 1748 } 1749 } 1750 1751 fiber = createFiber(fiberTag, pendingProps, key, mode); 1752 fiber.elementType = type; 1753 fiber.type = resolvedType; 1754 fiber.expirationTime = expirationTime; 1755 1756 return fiber; 1757 } 1758 1759 function createFiberFromElement(element, mode, expirationTime) { 1760 var owner = null; 1761 var type = element.type; 1762 var key = element.key; 1763 var pendingProps = element.props; 1764 var fiber = createFiberFromTypeAndProps(type, key, pendingProps, owner, mode, expirationTime); 1765 return fiber; 1766 } 1767 1768 function createFiberFromFragment(elements, mode, expirationTime, key) { 1769 var fiber = createFiber(Fragment, elements, key, mode); 1770 fiber.expirationTime = expirationTime; 1771 return fiber; 1772 } 1773 1774 function createFiberFromProfiler(pendingProps, mode, expirationTime, key) { 1775 var fiber = createFiber(Profiler, pendingProps, key, mode | ProfileMode); 1776 // TODO: The Profiler fiber shouldn't have a type. It has a tag. 1777 fiber.elementType = REACT_PROFILER_TYPE; 1778 fiber.type = REACT_PROFILER_TYPE; 1779 fiber.expirationTime = expirationTime; 1780 1781 return fiber; 1782 } 1783 1784 function createFiberFromMode(pendingProps, mode, expirationTime, key) { 1785 var fiber = createFiber(Mode, pendingProps, key, mode); 1786 1787 // TODO: The Mode fiber shouldn't have a type. It has a tag. 1788 var type = (mode & ConcurrentMode) === NoContext ? REACT_STRICT_MODE_TYPE : REACT_CONCURRENT_MODE_TYPE; 1789 fiber.elementType = type; 1790 fiber.type = type; 1791 1792 fiber.expirationTime = expirationTime; 1793 return fiber; 1794 } 1795 1796 function createFiberFromSuspense(pendingProps, mode, expirationTime, key) { 1797 var fiber = createFiber(SuspenseComponent, pendingProps, key, mode); 1798 1799 // TODO: The SuspenseComponent fiber shouldn't have a type. It has a tag. 1800 var type = REACT_SUSPENSE_TYPE; 1801 fiber.elementType = type; 1802 fiber.type = type; 1803 1804 fiber.expirationTime = expirationTime; 1805 return fiber; 1806 } 1807 1808 function createFiberFromText(content, mode, expirationTime) { 1809 var fiber = createFiber(HostText, content, null, mode); 1810 fiber.expirationTime = expirationTime; 1811 return fiber; 1812 } 1813 1814 function createFiberFromHostInstanceForDeletion() { 1815 var fiber = createFiber(HostComponent, null, null, NoContext); 1816 // TODO: These should not need a type. 1817 fiber.elementType = 'DELETED'; 1818 fiber.type = 'DELETED'; 1819 return fiber; 1820 } 1821 1822 function createFiberFromPortal(portal, mode, expirationTime) { 1823 var pendingProps = portal.children !== null ? portal.children : []; 1824 var fiber = createFiber(HostPortal, pendingProps, portal.key, mode); 1825 fiber.expirationTime = expirationTime; 1826 fiber.stateNode = { 1827 containerInfo: portal.containerInfo, 1828 pendingChildren: null, // Used by persistent updates 1829 implementation: portal.implementation 1830 }; 1831 return fiber; 1832 } 1833 1834 // Used for stashing WIP properties to replay failed work in DEV. 1835 1836 var ReactInternals$1 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 1837 1838 var _ReactInternals$Sched = ReactInternals$1.SchedulerTracing; 1839 var __interactionsRef = _ReactInternals$Sched.__interactionsRef; 1840 var __subscriberRef = _ReactInternals$Sched.__subscriberRef; 1841 var unstable_clear = _ReactInternals$Sched.unstable_clear; 1842 var unstable_getCurrent = _ReactInternals$Sched.unstable_getCurrent; 1843 var unstable_getThreadID = _ReactInternals$Sched.unstable_getThreadID; 1844 var unstable_subscribe = _ReactInternals$Sched.unstable_subscribe; 1845 var unstable_trace = _ReactInternals$Sched.unstable_trace; 1846 var unstable_unsubscribe = _ReactInternals$Sched.unstable_unsubscribe; 1847 var unstable_wrap = _ReactInternals$Sched.unstable_wrap; 1848 1849 // TODO: This should be lifted into the renderer. 1850 1851 1852 // The following attributes are only used by interaction tracing builds. 1853 // They enable interactions to be associated with their async work, 1854 // And expose interaction metadata to the React DevTools Profiler plugin. 1855 // Note that these attributes are only defined when the enableSchedulerTracing flag is enabled. 1856 1857 1858 // Exported FiberRoot type includes all properties, 1859 // To avoid requiring potentially error-prone :any casts throughout the project. 1860 // Profiling properties are only safe to access in profiling builds (when enableSchedulerTracing is true). 1861 // The types are defined separately within this file to ensure they stay in sync. 1862 // (We don't have to use an inline :any cast when enableSchedulerTracing is disabled.) 1863 1864 1865 function createFiberRoot(containerInfo, isConcurrent, hydrate) { 1866 // Cyclic construction. This cheats the type system right now because 1867 // stateNode is any. 1868 var uninitializedFiber = createHostRootFiber(isConcurrent); 1869 1870 var root = void 0; 1871 if (enableSchedulerTracing) { 1872 root = { 1873 current: uninitializedFiber, 1874 containerInfo: containerInfo, 1875 pendingChildren: null, 1876 1877 earliestPendingTime: NoWork, 1878 latestPendingTime: NoWork, 1879 earliestSuspendedTime: NoWork, 1880 latestSuspendedTime: NoWork, 1881 latestPingedTime: NoWork, 1882 1883 pingCache: null, 1884 1885 didError: false, 1886 1887 pendingCommitExpirationTime: NoWork, 1888 finishedWork: null, 1889 timeoutHandle: noTimeout, 1890 context: null, 1891 pendingContext: null, 1892 hydrate: hydrate, 1893 nextExpirationTimeToWorkOn: NoWork, 1894 expirationTime: NoWork, 1895 firstBatch: null, 1896 nextScheduledRoot: null, 1897 1898 interactionThreadID: unstable_getThreadID(), 1899 memoizedInteractions: new Set(), 1900 pendingInteractionMap: new Map() 1901 }; 1902 } else { 1903 root = { 1904 current: uninitializedFiber, 1905 containerInfo: containerInfo, 1906 pendingChildren: null, 1907 1908 pingCache: null, 1909 1910 earliestPendingTime: NoWork, 1911 latestPendingTime: NoWork, 1912 earliestSuspendedTime: NoWork, 1913 latestSuspendedTime: NoWork, 1914 latestPingedTime: NoWork, 1915 1916 didError: false, 1917 1918 pendingCommitExpirationTime: NoWork, 1919 finishedWork: null, 1920 timeoutHandle: noTimeout, 1921 context: null, 1922 pendingContext: null, 1923 hydrate: hydrate, 1924 nextExpirationTimeToWorkOn: NoWork, 1925 expirationTime: NoWork, 1926 firstBatch: null, 1927 nextScheduledRoot: null 1928 }; 1929 } 1930 1931 uninitializedFiber.stateNode = root; 1932 1933 // The reason for the way the Flow types are structured in this file, 1934 // Is to avoid needing :any casts everywhere interaction tracing fields are used. 1935 // Unfortunately that requires an :any cast for non-interaction tracing capable builds. 1936 // $FlowFixMe Remove this :any cast and replace it with something better. 1937 return root; 1938 } 1939 1940 var ReactInternals$2 = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; 1941 1942 var _ReactInternals$Sched$1 = ReactInternals$2.Scheduler; 1943 var unstable_cancelCallback = _ReactInternals$Sched$1.unstable_cancelCallback; 1944 var unstable_now = _ReactInternals$Sched$1.unstable_now; 1945 var unstable_scheduleCallback = _ReactInternals$Sched$1.unstable_scheduleCallback; 1946 var unstable_shouldYield = _ReactInternals$Sched$1.unstable_shouldYield; 1947 var unstable_getFirstCallbackNode = _ReactInternals$Sched$1.unstable_getFirstCallbackNode; 1948 var unstable_runWithPriority = _ReactInternals$Sched$1.unstable_runWithPriority; 1949 var unstable_next = _ReactInternals$Sched$1.unstable_next; 1950 var unstable_continueExecution = _ReactInternals$Sched$1.unstable_continueExecution; 1951 var unstable_pauseExecution = _ReactInternals$Sched$1.unstable_pauseExecution; 1952 var unstable_getCurrentPriorityLevel = _ReactInternals$Sched$1.unstable_getCurrentPriorityLevel; 1953 var unstable_ImmediatePriority = _ReactInternals$Sched$1.unstable_ImmediatePriority; 1954 var unstable_UserBlockingPriority = _ReactInternals$Sched$1.unstable_UserBlockingPriority; 1955 var unstable_NormalPriority = _ReactInternals$Sched$1.unstable_NormalPriority; 1956 var unstable_LowPriority = _ReactInternals$Sched$1.unstable_LowPriority; 1957 var unstable_IdlePriority = _ReactInternals$Sched$1.unstable_IdlePriority; 1958 1959 /** 1960 * Call a function while guarding against errors that happens within it. 1961 * Returns an error if it throws, otherwise null. 1962 * 1963 * In production, this is implemented using a try-catch. The reason we don't 1964 * use a try-catch directly is so that we can swap out a different 1965 * implementation in DEV mode. 1966 * 1967 * @param {String} name of the guard to use for logging or debugging 1968 * @param {Function} func The function to invoke 1969 * @param {*} context The context to use when calling the function 1970 * @param {...*} args Arguments for function 1971 */ 1972 1973 1974 /** 1975 * Same as invokeGuardedCallback, but instead of returning an error, it stores 1976 * it in a global so it can be rethrown by `rethrowCaughtError` later. 1977 * TODO: See if caughtError and rethrowError can be unified. 1978 * 1979 * @param {String} name of the guard to use for logging or debugging 1980 * @param {Function} func The function to invoke 1981 * @param {*} context The context to use when calling the function 1982 * @param {...*} args Arguments for function 1983 */ 1984 1985 1986 /** 1987 * During execution of guarded functions we will capture the first error which 1988 * we will rethrow to be handled by the top level error handler. 1989 */ 1990 1991 /** 1992 * Forked from fbjs/warning: 1993 * https://github.com/facebook/fbjs/blob/e66ba20ad5be433eb54423f2b097d829324d9de6/packages/fbjs/src/__forks__/warning.js 1994 * 1995 * Only change is we use console.warn instead of console.error, 1996 * and do nothing when 'console' is not supported. 1997 * This really simplifies the code. 1998 * --- 1999 * Similar to invariant but only logs a warning if the condition is not met. 2000 * This can be used to log issues in development environments in critical 2001 * paths. Removing the logging code for production environments will keep the 2002 * same logic and follow the same code paths. 2003 */ 2004 2005 // This lets us hook into Fiber to debug what it's doing. 2006 // See https://github.com/facebook/react/pull/8033. 2007 // This is not part of the public API, not even for React DevTools. 2008 // You may only inject a debugTool if you work on React Fiber itself. 2009 2010 // TODO: Offscreen updates should never suspend. However, a promise that 2011 // suspended inside an offscreen subtree should be able to ping at the priority 2012 // of the outer render. 2013 2014 function markPendingPriorityLevel(root, expirationTime) { 2015 // If there's a gap between completing a failed root and retrying it, 2016 // additional updates may be scheduled. Clear `didError`, in case the update 2017 // is sufficient to fix the error. 2018 root.didError = false; 2019 2020 // Update the latest and earliest pending times 2021 var earliestPendingTime = root.earliestPendingTime; 2022 if (earliestPendingTime === NoWork) { 2023 // No other pending updates. 2024 root.earliestPendingTime = root.latestPendingTime = expirationTime; 2025 } else { 2026 if (earliestPendingTime < expirationTime) { 2027 // This is the earliest pending update. 2028 root.earliestPendingTime = expirationTime; 2029 } else { 2030 var latestPendingTime = root.latestPendingTime; 2031 if (latestPendingTime > expirationTime) { 2032 // This is the latest pending update 2033 root.latestPendingTime = expirationTime; 2034 } 2035 } 2036 } 2037 findNextExpirationTimeToWorkOn(expirationTime, root); 2038 } 2039 2040 function markCommittedPriorityLevels(root, earliestRemainingTime) { 2041 root.didError = false; 2042 2043 if (earliestRemainingTime === NoWork) { 2044 // Fast path. There's no remaining work. Clear everything. 2045 root.earliestPendingTime = NoWork; 2046 root.latestPendingTime = NoWork; 2047 root.earliestSuspendedTime = NoWork; 2048 root.latestSuspendedTime = NoWork; 2049 root.latestPingedTime = NoWork; 2050 findNextExpirationTimeToWorkOn(NoWork, root); 2051 return; 2052 } 2053 2054 if (earliestRemainingTime < root.latestPingedTime) { 2055 root.latestPingedTime = NoWork; 2056 } 2057 2058 // Let's see if the previous latest known pending level was just flushed. 2059 var latestPendingTime = root.latestPendingTime; 2060 if (latestPendingTime !== NoWork) { 2061 if (latestPendingTime > earliestRemainingTime) { 2062 // We've flushed all the known pending levels. 2063 root.earliestPendingTime = root.latestPendingTime = NoWork; 2064 } else { 2065 var earliestPendingTime = root.earliestPendingTime; 2066 if (earliestPendingTime > earliestRemainingTime) { 2067 // We've flushed the earliest known pending level. Set this to the 2068 // latest pending time. 2069 root.earliestPendingTime = root.latestPendingTime; 2070 } 2071 } 2072 } 2073 2074 // Now let's handle the earliest remaining level in the whole tree. We need to 2075 // decide whether to treat it as a pending level or as suspended. Check 2076 // it falls within the range of known suspended levels. 2077 2078 var earliestSuspendedTime = root.earliestSuspendedTime; 2079 if (earliestSuspendedTime === NoWork) { 2080 // There's no suspended work. Treat the earliest remaining level as a 2081 // pending level. 2082 markPendingPriorityLevel(root, earliestRemainingTime); 2083 findNextExpirationTimeToWorkOn(NoWork, root); 2084 return; 2085 } 2086 2087 var latestSuspendedTime = root.latestSuspendedTime; 2088 if (earliestRemainingTime < latestSuspendedTime) { 2089 // The earliest remaining level is later than all the suspended work. That 2090 // means we've flushed all the suspended work. 2091 root.earliestSuspendedTime = NoWork; 2092 root.latestSuspendedTime = NoWork; 2093 root.latestPingedTime = NoWork; 2094 2095 // There's no suspended work. Treat the earliest remaining level as a 2096 // pending level. 2097 markPendingPriorityLevel(root, earliestRemainingTime); 2098 findNextExpirationTimeToWorkOn(NoWork, root); 2099 return; 2100 } 2101 2102 if (earliestRemainingTime > earliestSuspendedTime) { 2103 // The earliest remaining time is earlier than all the suspended work. 2104 // Treat it as a pending update. 2105 markPendingPriorityLevel(root, earliestRemainingTime); 2106 findNextExpirationTimeToWorkOn(NoWork, root); 2107 return; 2108 } 2109 2110 // The earliest remaining time falls within the range of known suspended 2111 // levels. We should treat this as suspended work. 2112 findNextExpirationTimeToWorkOn(NoWork, root); 2113 } 2114 2115 function hasLowerPriorityWork(root, erroredExpirationTime) { 2116 var latestPendingTime = root.latestPendingTime; 2117 var latestSuspendedTime = root.latestSuspendedTime; 2118 var latestPingedTime = root.latestPingedTime; 2119 return latestPendingTime !== NoWork && latestPendingTime < erroredExpirationTime || latestSuspendedTime !== NoWork && latestSuspendedTime < erroredExpirationTime || latestPingedTime !== NoWork && latestPingedTime < erroredExpirationTime; 2120 } 2121 2122 function isPriorityLevelSuspended(root, expirationTime) { 2123 var earliestSuspendedTime = root.earliestSuspendedTime; 2124 var latestSuspendedTime = root.latestSuspendedTime; 2125 return earliestSuspendedTime !== NoWork && expirationTime <= earliestSuspendedTime && expirationTime >= latestSuspendedTime; 2126 } 2127 2128 function markSuspendedPriorityLevel(root, suspendedTime) { 2129 root.didError = false; 2130 clearPing(root, suspendedTime); 2131 2132 // First, check the known pending levels and update them if needed. 2133 var earliestPendingTime = root.earliestPendingTime; 2134 var latestPendingTime = root.latestPendingTime; 2135 if (earliestPendingTime === suspendedTime) { 2136 if (latestPendingTime === suspendedTime) { 2137 // Both known pending levels were suspended. Clear them. 2138 root.earliestPendingTime = root.latestPendingTime = NoWork; 2139 } else { 2140 // The earliest pending level was suspended. Clear by setting it to the 2141 // latest pending level. 2142 root.earliestPendingTime = latestPendingTime; 2143 } 2144 } else if (latestPendingTime === suspendedTime) { 2145 // The latest pending level was suspended. Clear by setting it to the 2146 // latest pending level. 2147 root.latestPendingTime = earliestPendingTime; 2148 } 2149 2150 // Finally, update the known suspended levels. 2151 var earliestSuspendedTime = root.earliestSuspendedTime; 2152 var latestSuspendedTime = root.latestSuspendedTime; 2153 if (earliestSuspendedTime === NoWork) { 2154 // No other suspended levels. 2155 root.earliestSuspendedTime = root.latestSuspendedTime = suspendedTime; 2156 } else { 2157 if (earliestSuspendedTime < suspendedTime) { 2158 // This is the earliest suspended level. 2159 root.earliestSuspendedTime = suspendedTime; 2160 } else if (latestSuspendedTime > suspendedTime) { 2161 // This is the latest suspended level 2162 root.latestSuspendedTime = suspendedTime; 2163 } 2164 } 2165 2166 findNextExpirationTimeToWorkOn(suspendedTime, root); 2167 } 2168 2169 function markPingedPriorityLevel(root, pingedTime) { 2170 root.didError = false; 2171 2172 // TODO: When we add back resuming, we need to ensure the progressed work 2173 // is thrown out and not reused during the restarted render. One way to 2174 // invalidate the progressed work is to restart at expirationTime + 1. 2175 var latestPingedTime = root.latestPingedTime; 2176 if (latestPingedTime === NoWork || latestPingedTime > pingedTime) { 2177 root.latestPingedTime = pingedTime; 2178 } 2179 findNextExpirationTimeToWorkOn(pingedTime, root); 2180 } 2181 2182 function clearPing(root, completedTime) { 2183 var latestPingedTime = root.latestPingedTime; 2184 if (latestPingedTime >= completedTime) { 2185 root.latestPingedTime = NoWork; 2186 } 2187 } 2188 2189 function findEarliestOutstandingPriorityLevel(root, renderExpirationTime) { 2190 var earliestExpirationTime = renderExpirationTime; 2191 2192 var earliestPendingTime = root.earliestPendingTime; 2193 var earliestSuspendedTime = root.earliestSuspendedTime; 2194 if (earliestPendingTime > earliestExpirationTime) { 2195 earliestExpirationTime = earliestPendingTime; 2196 } 2197 if (earliestSuspendedTime > earliestExpirationTime) { 2198 earliestExpirationTime = earliestSuspendedTime; 2199 } 2200 return earliestExpirationTime; 2201 } 2202 2203 function didExpireAtExpirationTime(root, currentTime) { 2204 var expirationTime = root.expirationTime; 2205 if (expirationTime !== NoWork && currentTime <= expirationTime) { 2206 // The root has expired. Flush all work up to the current time. 2207 root.nextExpirationTimeToWorkOn = currentTime; 2208 } 2209 } 2210 2211 function findNextExpirationTimeToWorkOn(completedExpirationTime, root) { 2212 var earliestSuspendedTime = root.earliestSuspendedTime; 2213 var latestSuspendedTime = root.latestSuspendedTime; 2214 var earliestPendingTime = root.earliestPendingTime; 2215 var latestPingedTime = root.latestPingedTime; 2216 2217 // Work on the earliest pending time. Failing that, work on the latest 2218 // pinged time. 2219 var nextExpirationTimeToWorkOn = earliestPendingTime !== NoWork ? earliestPendingTime : latestPingedTime; 2220 2221 // If there is no pending or pinged work, check if there's suspended work 2222 // that's lower priority than what we just completed. 2223 if (nextExpirationTimeToWorkOn === NoWork && (completedExpirationTime === NoWork || latestSuspendedTime < completedExpirationTime)) { 2224 // The lowest priority suspended work is the work most likely to be 2225 // committed next. Let's start rendering it again, so that if it times out, 2226 // it's ready to commit. 2227 nextExpirationTimeToWorkOn = latestSuspendedTime; 2228 } 2229 2230 var expirationTime = nextExpirationTimeToWorkOn; 2231 if (expirationTime !== NoWork && earliestSuspendedTime > expirationTime) { 2232 // Expire using the earliest known expiration time. 2233 expirationTime = earliestSuspendedTime; 2234 } 2235 2236 root.nextExpirationTimeToWorkOn = nextExpirationTimeToWorkOn; 2237 root.expirationTime = expirationTime; 2238 } 2239 2240 /** 2241 * inlined Object.is polyfill to avoid requiring consumers ship their own 2242 * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 2243 */ 2244 function is(x, y) { 2245 return x === y && (x !== 0 || 1 / x === 1 / y) || x !== x && y !== y // eslint-disable-line no-self-compare 2246 ; 2247 } 2248 2249 var hasOwnProperty = Object.prototype.hasOwnProperty; 2250 2251 /** 2252 * Performs equality by iterating through keys on an object and returning false 2253 * when any key has values which are not strictly equal between the arguments. 2254 * Returns true when the values of all keys are strictly equal. 2255 */ 2256 function shallowEqual(objA, objB) { 2257 if (is(objA, objB)) { 2258 return true; 2259 } 2260 2261 if (typeof objA !== 'object' || objA === null || typeof objB !== 'object' || objB === null) { 2262 return false; 2263 } 2264 2265 var keysA = Object.keys(objA); 2266 var keysB = Object.keys(objB); 2267 2268 if (keysA.length !== keysB.length) { 2269 return false; 2270 } 2271 2272 // Test for A's keys different from B. 2273 for (var i = 0; i < keysA.length; i++) { 2274 if (!hasOwnProperty.call(objB, keysA[i]) || !is(objA[keysA[i]], objB[keysA[i]])) { 2275 return false; 2276 } 2277 } 2278 2279 return true; 2280 } 2281 2282 function resolveDefaultProps(Component, baseProps) { 2283 if (Component && Component.defaultProps) { 2284 // Resolve default props. Taken from ReactElement 2285 var props = _assign({}, baseProps); 2286 var defaultProps = Component.defaultProps; 2287 for (var propName in defaultProps) { 2288 if (props[propName] === undefined) { 2289 props[propName] = defaultProps[propName]; 2290 } 2291 } 2292 return props; 2293 } 2294 return baseProps; 2295 } 2296 2297 function readLazyComponentType(lazyComponent) { 2298 var status = lazyComponent._status; 2299 var result = lazyComponent._result; 2300 switch (status) { 2301 case Resolved: 2302 { 2303 var Component = result; 2304 return Component; 2305 } 2306 case Rejected: 2307 { 2308 var error = result; 2309 throw error; 2310 } 2311 case Pending: 2312 { 2313 var thenable = result; 2314 throw thenable; 2315 } 2316 default: 2317 { 2318 lazyComponent._status = Pending; 2319 var ctor = lazyComponent._ctor; 2320 var _thenable = ctor(); 2321 _thenable.then(function (moduleObject) { 2322 if (lazyComponent._status === Pending) { 2323 var defaultExport = moduleObject.default; 2324 lazyComponent._status = Resolved; 2325 lazyComponent._result = defaultExport; 2326 } 2327 }, function (error) { 2328 if (lazyComponent._status === Pending) { 2329 lazyComponent._status = Rejected; 2330 lazyComponent._result = error; 2331 } 2332 }); 2333 // Handle synchronous thenables. 2334 switch (lazyComponent._status) { 2335 case Resolved: 2336 return lazyComponent._result; 2337 case Rejected: 2338 throw lazyComponent._result; 2339 } 2340 lazyComponent._result = _thenable; 2341 throw _thenable; 2342 } 2343 } 2344 } 2345 2346 // React.Component uses a shared frozen object by default. 2347 // We'll use it to determine whether we need to initialize legacy refs. 2348 var emptyRefsObject = new React.Component().refs; 2349 2350 function applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, nextProps) { 2351 var prevState = workInProgress.memoizedState; 2352 2353 var partialState = getDerivedStateFromProps(nextProps, prevState); 2354 2355 var memoizedState = partialState === null || partialState === undefined ? prevState : _assign({}, prevState, partialState); 2356 workInProgress.memoizedState = memoizedState; 2357 2358 // Once the update queue is empty, persist the derived state onto the 2359 // base state. 2360 var updateQueue = workInProgress.updateQueue; 2361 if (updateQueue !== null && workInProgress.expirationTime === NoWork) { 2362 updateQueue.baseState = memoizedState; 2363 } 2364 } 2365 2366 var classComponentUpdater = { 2367 isMounted: isMounted, 2368 enqueueSetState: function (inst, payload, callback) { 2369 var fiber = get(inst); 2370 var currentTime = requestCurrentTime(); 2371 var expirationTime = computeExpirationForFiber(currentTime, fiber); 2372 2373 var update = createUpdate(expirationTime); 2374 update.payload = payload; 2375 if (callback !== undefined && callback !== null) { 2376 update.callback = callback; 2377 } 2378 2379 flushPassiveEffects$1(); 2380 enqueueUpdate(fiber, update); 2381 scheduleWork(fiber, expirationTime); 2382 }, 2383 enqueueReplaceState: function (inst, payload, callback) { 2384 var fiber = get(inst); 2385 var currentTime = requestCurrentTime(); 2386 var expirationTime = computeExpirationForFiber(currentTime, fiber); 2387 2388 var update = createUpdate(expirationTime); 2389 update.tag = ReplaceState; 2390 update.payload = payload; 2391 2392 if (callback !== undefined && callback !== null) { 2393 update.callback = callback; 2394 } 2395 2396 flushPassiveEffects$1(); 2397 enqueueUpdate(fiber, update); 2398 scheduleWork(fiber, expirationTime); 2399 }, 2400 enqueueForceUpdate: function (inst, callback) { 2401 var fiber = get(inst); 2402 var currentTime = requestCurrentTime(); 2403 var expirationTime = computeExpirationForFiber(currentTime, fiber); 2404 2405 var update = createUpdate(expirationTime); 2406 update.tag = ForceUpdate; 2407 2408 if (callback !== undefined && callback !== null) { 2409 update.callback = callback; 2410 } 2411 2412 flushPassiveEffects$1(); 2413 enqueueUpdate(fiber, update); 2414 scheduleWork(fiber, expirationTime); 2415 } 2416 }; 2417 2418 function checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext) { 2419 var instance = workInProgress.stateNode; 2420 if (typeof instance.shouldComponentUpdate === 'function') { 2421 startPhaseTimer(workInProgress, 'shouldComponentUpdate'); 2422 var shouldUpdate = instance.shouldComponentUpdate(newProps, newState, nextContext); 2423 stopPhaseTimer(); 2424 2425 return shouldUpdate; 2426 } 2427 2428 if (ctor.prototype && ctor.prototype.isPureReactComponent) { 2429 return !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState); 2430 } 2431 2432 return true; 2433 } 2434 2435 function adoptClassInstance(workInProgress, instance) { 2436 instance.updater = classComponentUpdater; 2437 workInProgress.stateNode = instance; 2438 // The instance needs access to the fiber so that it can schedule updates 2439 set(instance, workInProgress); 2440 2441 } 2442 2443 function constructClassInstance(workInProgress, ctor, props, renderExpirationTime) { 2444 var isLegacyContextConsumer = false; 2445 var unmaskedContext = emptyContextObject; 2446 var context = null; 2447 var contextType = ctor.contextType; 2448 2449 if (typeof contextType === 'object' && contextType !== null) { 2450 context = readContext(contextType); 2451 } else { 2452 unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 2453 var contextTypes = ctor.contextTypes; 2454 isLegacyContextConsumer = contextTypes !== null && contextTypes !== undefined; 2455 context = isLegacyContextConsumer ? getMaskedContext(workInProgress, unmaskedContext) : emptyContextObject; 2456 } 2457 2458 // Instantiate twice to help detect side-effects. 2459 var instance = new ctor(props, context); 2460 var state = workInProgress.memoizedState = instance.state !== null && instance.state !== undefined ? instance.state : null; 2461 adoptClassInstance(workInProgress, instance); 2462 2463 if (isLegacyContextConsumer) { 2464 cacheContext(workInProgress, unmaskedContext, context); 2465 } 2466 2467 return instance; 2468 } 2469 2470 function callComponentWillMount(workInProgress, instance) { 2471 startPhaseTimer(workInProgress, 'componentWillMount'); 2472 var oldState = instance.state; 2473 2474 if (typeof instance.componentWillMount === 'function') { 2475 instance.componentWillMount(); 2476 } 2477 if (typeof instance.UNSAFE_componentWillMount === 'function') { 2478 instance.UNSAFE_componentWillMount(); 2479 } 2480 2481 stopPhaseTimer(); 2482 2483 if (oldState !== instance.state) { 2484 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); 2485 } 2486 } 2487 2488 function callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext) { 2489 var oldState = instance.state; 2490 startPhaseTimer(workInProgress, 'componentWillReceiveProps'); 2491 if (typeof instance.componentWillReceiveProps === 'function') { 2492 instance.componentWillReceiveProps(newProps, nextContext); 2493 } 2494 if (typeof instance.UNSAFE_componentWillReceiveProps === 'function') { 2495 instance.UNSAFE_componentWillReceiveProps(newProps, nextContext); 2496 } 2497 stopPhaseTimer(); 2498 2499 if (instance.state !== oldState) { 2500 classComponentUpdater.enqueueReplaceState(instance, instance.state, null); 2501 } 2502 } 2503 2504 // Invokes the mount life-cycles on a previously never rendered instance. 2505 function mountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { 2506 var instance = workInProgress.stateNode; 2507 instance.props = newProps; 2508 instance.state = workInProgress.memoizedState; 2509 instance.refs = emptyRefsObject; 2510 2511 var contextType = ctor.contextType; 2512 if (typeof contextType === 'object' && contextType !== null) { 2513 instance.context = readContext(contextType); 2514 } else { 2515 var unmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 2516 instance.context = getMaskedContext(workInProgress, unmaskedContext); 2517 } 2518 2519 var updateQueue = workInProgress.updateQueue; 2520 if (updateQueue !== null) { 2521 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 2522 instance.state = workInProgress.memoizedState; 2523 } 2524 2525 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 2526 if (typeof getDerivedStateFromProps === 'function') { 2527 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 2528 instance.state = workInProgress.memoizedState; 2529 } 2530 2531 // In order to support react-lifecycles-compat polyfilled components, 2532 // Unsafe lifecycles should not be invoked for components using the new APIs. 2533 if (typeof ctor.getDerivedStateFromProps !== 'function' && typeof instance.getSnapshotBeforeUpdate !== 'function' && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { 2534 callComponentWillMount(workInProgress, instance); 2535 // If we had additional state updates during this life-cycle, let's 2536 // process them now. 2537 updateQueue = workInProgress.updateQueue; 2538 if (updateQueue !== null) { 2539 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 2540 instance.state = workInProgress.memoizedState; 2541 } 2542 } 2543 2544 if (typeof instance.componentDidMount === 'function') { 2545 workInProgress.effectTag |= Update; 2546 } 2547 } 2548 2549 function resumeMountClassInstance(workInProgress, ctor, newProps, renderExpirationTime) { 2550 var instance = workInProgress.stateNode; 2551 2552 var oldProps = workInProgress.memoizedProps; 2553 instance.props = oldProps; 2554 2555 var oldContext = instance.context; 2556 var contextType = ctor.contextType; 2557 var nextContext = void 0; 2558 if (typeof contextType === 'object' && contextType !== null) { 2559 nextContext = readContext(contextType); 2560 } else { 2561 var nextLegacyUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 2562 nextContext = getMaskedContext(workInProgress, nextLegacyUnmaskedContext); 2563 } 2564 2565 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 2566 var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; 2567 2568 // Note: During these life-cycles, instance.props/instance.state are what 2569 // ever the previously attempted to render - not the "current". However, 2570 // during componentDidUpdate we pass the "current" props. 2571 2572 // In order to support react-lifecycles-compat polyfilled components, 2573 // Unsafe lifecycles should not be invoked for components using the new APIs. 2574 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { 2575 if (oldProps !== newProps || oldContext !== nextContext) { 2576 callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); 2577 } 2578 } 2579 2580 resetHasForceUpdateBeforeProcessing(); 2581 2582 var oldState = workInProgress.memoizedState; 2583 var newState = instance.state = oldState; 2584 var updateQueue = workInProgress.updateQueue; 2585 if (updateQueue !== null) { 2586 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 2587 newState = workInProgress.memoizedState; 2588 } 2589 if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { 2590 // If an update was already in progress, we should schedule an Update 2591 // effect even though we're bailing out, so that cWU/cDU are called. 2592 if (typeof instance.componentDidMount === 'function') { 2593 workInProgress.effectTag |= Update; 2594 } 2595 return false; 2596 } 2597 2598 if (typeof getDerivedStateFromProps === 'function') { 2599 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 2600 newState = workInProgress.memoizedState; 2601 } 2602 2603 var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); 2604 2605 if (shouldUpdate) { 2606 // In order to support react-lifecycles-compat polyfilled components, 2607 // Unsafe lifecycles should not be invoked for components using the new APIs. 2608 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function')) { 2609 startPhaseTimer(workInProgress, 'componentWillMount'); 2610 if (typeof instance.componentWillMount === 'function') { 2611 instance.componentWillMount(); 2612 } 2613 if (typeof instance.UNSAFE_componentWillMount === 'function') { 2614 instance.UNSAFE_componentWillMount(); 2615 } 2616 stopPhaseTimer(); 2617 } 2618 if (typeof instance.componentDidMount === 'function') { 2619 workInProgress.effectTag |= Update; 2620 } 2621 } else { 2622 // If an update was already in progress, we should schedule an Update 2623 // effect even though we're bailing out, so that cWU/cDU are called. 2624 if (typeof instance.componentDidMount === 'function') { 2625 workInProgress.effectTag |= Update; 2626 } 2627 2628 // If shouldComponentUpdate returned false, we should still update the 2629 // memoized state to indicate that this work can be reused. 2630 workInProgress.memoizedProps = newProps; 2631 workInProgress.memoizedState = newState; 2632 } 2633 2634 // Update the existing instance's state, props, and context pointers even 2635 // if shouldComponentUpdate returns false. 2636 instance.props = newProps; 2637 instance.state = newState; 2638 instance.context = nextContext; 2639 2640 return shouldUpdate; 2641 } 2642 2643 // Invokes the update life-cycles and returns false if it shouldn't rerender. 2644 function updateClassInstance(current, workInProgress, ctor, newProps, renderExpirationTime) { 2645 var instance = workInProgress.stateNode; 2646 2647 var oldProps = workInProgress.memoizedProps; 2648 instance.props = workInProgress.type === workInProgress.elementType ? oldProps : resolveDefaultProps(workInProgress.type, oldProps); 2649 2650 var oldContext = instance.context; 2651 var contextType = ctor.contextType; 2652 var nextContext = void 0; 2653 if (typeof contextType === 'object' && contextType !== null) { 2654 nextContext = readContext(contextType); 2655 } else { 2656 var nextUnmaskedContext = getUnmaskedContext(workInProgress, ctor, true); 2657 nextContext = getMaskedContext(workInProgress, nextUnmaskedContext); 2658 } 2659 2660 var getDerivedStateFromProps = ctor.getDerivedStateFromProps; 2661 var hasNewLifecycles = typeof getDerivedStateFromProps === 'function' || typeof instance.getSnapshotBeforeUpdate === 'function'; 2662 2663 // Note: During these life-cycles, instance.props/instance.state are what 2664 // ever the previously attempted to render - not the "current". However, 2665 // during componentDidUpdate we pass the "current" props. 2666 2667 // In order to support react-lifecycles-compat polyfilled components, 2668 // Unsafe lifecycles should not be invoked for components using the new APIs. 2669 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function')) { 2670 if (oldProps !== newProps || oldContext !== nextContext) { 2671 callComponentWillReceiveProps(workInProgress, instance, newProps, nextContext); 2672 } 2673 } 2674 2675 resetHasForceUpdateBeforeProcessing(); 2676 2677 var oldState = workInProgress.memoizedState; 2678 var newState = instance.state = oldState; 2679 var updateQueue = workInProgress.updateQueue; 2680 if (updateQueue !== null) { 2681 processUpdateQueue(workInProgress, updateQueue, newProps, instance, renderExpirationTime); 2682 newState = workInProgress.memoizedState; 2683 } 2684 2685 if (oldProps === newProps && oldState === newState && !hasContextChanged() && !checkHasForceUpdateAfterProcessing()) { 2686 // If an update was already in progress, we should schedule an Update 2687 // effect even though we're bailing out, so that cWU/cDU are called. 2688 if (typeof instance.componentDidUpdate === 'function') { 2689 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 2690 workInProgress.effectTag |= Update; 2691 } 2692 } 2693 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 2694 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 2695 workInProgress.effectTag |= Snapshot; 2696 } 2697 } 2698 return false; 2699 } 2700 2701 if (typeof getDerivedStateFromProps === 'function') { 2702 applyDerivedStateFromProps(workInProgress, ctor, getDerivedStateFromProps, newProps); 2703 newState = workInProgress.memoizedState; 2704 } 2705 2706 var shouldUpdate = checkHasForceUpdateAfterProcessing() || checkShouldComponentUpdate(workInProgress, ctor, oldProps, newProps, oldState, newState, nextContext); 2707 2708 if (shouldUpdate) { 2709 // In order to support react-lifecycles-compat polyfilled components, 2710 // Unsafe lifecycles should not be invoked for components using the new APIs. 2711 if (!hasNewLifecycles && (typeof instance.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function')) { 2712 startPhaseTimer(workInProgress, 'componentWillUpdate'); 2713 if (typeof instance.componentWillUpdate === 'function') { 2714 instance.componentWillUpdate(newProps, newState, nextContext); 2715 } 2716 if (typeof instance.UNSAFE_componentWillUpdate === 'function') { 2717 instance.UNSAFE_componentWillUpdate(newProps, newState, nextContext); 2718 } 2719 stopPhaseTimer(); 2720 } 2721 if (typeof instance.componentDidUpdate === 'function') { 2722 workInProgress.effectTag |= Update; 2723 } 2724 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 2725 workInProgress.effectTag |= Snapshot; 2726 } 2727 } else { 2728 // If an update was already in progress, we should schedule an Update 2729 // effect even though we're bailing out, so that cWU/cDU are called. 2730 if (typeof instance.componentDidUpdate === 'function') { 2731 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 2732 workInProgress.effectTag |= Update; 2733 } 2734 } 2735 if (typeof instance.getSnapshotBeforeUpdate === 'function') { 2736 if (oldProps !== current.memoizedProps || oldState !== current.memoizedState) { 2737 workInProgress.effectTag |= Snapshot; 2738 } 2739 } 2740 2741 // If shouldComponentUpdate returned false, we should still update the 2742 // memoized props/state to indicate that this work can be reused. 2743 workInProgress.memoizedProps = newProps; 2744 workInProgress.memoizedState = newState; 2745 } 2746 2747 // Update the existing instance's state, props, and context pointers even 2748 // if shouldComponentUpdate returns false. 2749 instance.props = newProps; 2750 instance.state = newState; 2751 instance.context = nextContext; 2752 2753 return shouldUpdate; 2754 } 2755 2756 var isArray = Array.isArray; 2757 2758 function coerceRef(returnFiber, current$$1, element) { 2759 var mixedRef = element.ref; 2760 if (mixedRef !== null && typeof mixedRef !== 'function' && typeof mixedRef !== 'object') { 2761 if (element._owner) { 2762 var owner = element._owner; 2763 var inst = void 0; 2764 if (owner) { 2765 var ownerFiber = owner; 2766 !(ownerFiber.tag === ClassComponent) ? reactProdInvariant('309') : void 0; 2767 inst = ownerFiber.stateNode; 2768 } 2769 !inst ? reactProdInvariant('147', mixedRef) : void 0; 2770 var stringRef = '' + mixedRef; 2771 // Check if previous string ref matches new string ref 2772 if (current$$1 !== null && current$$1.ref !== null && typeof current$$1.ref === 'function' && current$$1.ref._stringRef === stringRef) { 2773 return current$$1.ref; 2774 } 2775 var ref = function (value) { 2776 var refs = inst.refs; 2777 if (refs === emptyRefsObject) { 2778 // This is a lazy pooled frozen object, so we need to initialize. 2779 refs = inst.refs = {}; 2780 } 2781 if (value === null) { 2782 delete refs[stringRef]; 2783 } else { 2784 refs[stringRef] = value; 2785 } 2786 }; 2787 ref._stringRef = stringRef; 2788 return ref; 2789 } else { 2790 !(typeof mixedRef === 'string') ? reactProdInvariant('284') : void 0; 2791 !element._owner ? reactProdInvariant('290', mixedRef) : void 0; 2792 } 2793 } 2794 return mixedRef; 2795 } 2796 2797 function throwOnInvalidObjectType(returnFiber, newChild) { 2798 if (returnFiber.type !== 'textarea') { 2799 var addendum = ''; 2800 reactProdInvariant('31', Object.prototype.toString.call(newChild) === '[object Object]' ? 'object with keys {' + Object.keys(newChild).join(', ') + '}' : newChild, addendum); 2801 } 2802 } 2803 2804 // This wrapper function exists because I expect to clone the code in each path 2805 // to be able to optimize each path individually by branching early. This needs 2806 // a compiler or we can do it manually. Helpers that don't need this branching 2807 // live outside of this function. 2808 function ChildReconciler(shouldTrackSideEffects) { 2809 function deleteChild(returnFiber, childToDelete) { 2810 if (!shouldTrackSideEffects) { 2811 // Noop. 2812 return; 2813 } 2814 // Deletions are added in reversed order so we add it to the front. 2815 // At this point, the return fiber's effect list is empty except for 2816 // deletions, so we can just append the deletion to the list. The remaining 2817 // effects aren't added until the complete phase. Once we implement 2818 // resuming, this may not be true. 2819 var last = returnFiber.lastEffect; 2820 if (last !== null) { 2821 last.nextEffect = childToDelete; 2822 returnFiber.lastEffect = childToDelete; 2823 } else { 2824 returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; 2825 } 2826 childToDelete.nextEffect = null; 2827 childToDelete.effectTag = Deletion; 2828 } 2829 2830 function deleteRemainingChildren(returnFiber, currentFirstChild) { 2831 if (!shouldTrackSideEffects) { 2832 // Noop. 2833 return null; 2834 } 2835 2836 // TODO: For the shouldClone case, this could be micro-optimized a bit by 2837 // assuming that after the first child we've already added everything. 2838 var childToDelete = currentFirstChild; 2839 while (childToDelete !== null) { 2840 deleteChild(returnFiber, childToDelete); 2841 childToDelete = childToDelete.sibling; 2842 } 2843 return null; 2844 } 2845 2846 function mapRemainingChildren(returnFiber, currentFirstChild) { 2847 // Add the remaining children to a temporary map so that we can find them by 2848 // keys quickly. Implicit (null) keys get added to this set with their index 2849 var existingChildren = new Map(); 2850 2851 var existingChild = currentFirstChild; 2852 while (existingChild !== null) { 2853 if (existingChild.key !== null) { 2854 existingChildren.set(existingChild.key, existingChild); 2855 } else { 2856 existingChildren.set(existingChild.index, existingChild); 2857 } 2858 existingChild = existingChild.sibling; 2859 } 2860 return existingChildren; 2861 } 2862 2863 function useFiber(fiber, pendingProps, expirationTime) { 2864 // We currently set sibling to null and index to 0 here because it is easy 2865 // to forget to do before returning it. E.g. for the single child case. 2866 var clone = createWorkInProgress(fiber, pendingProps, expirationTime); 2867 clone.index = 0; 2868 clone.sibling = null; 2869 return clone; 2870 } 2871 2872 function placeChild(newFiber, lastPlacedIndex, newIndex) { 2873 newFiber.index = newIndex; 2874 if (!shouldTrackSideEffects) { 2875 // Noop. 2876 return lastPlacedIndex; 2877 } 2878 var current$$1 = newFiber.alternate; 2879 if (current$$1 !== null) { 2880 var oldIndex = current$$1.index; 2881 if (oldIndex < lastPlacedIndex) { 2882 // This is a move. 2883 newFiber.effectTag = Placement; 2884 return lastPlacedIndex; 2885 } else { 2886 // This item can stay in place. 2887 return oldIndex; 2888 } 2889 } else { 2890 // This is an insertion. 2891 newFiber.effectTag = Placement; 2892 return lastPlacedIndex; 2893 } 2894 } 2895 2896 function placeSingleChild(newFiber) { 2897 // This is simpler for the single child case. We only need to do a 2898 // placement for inserting new children. 2899 if (shouldTrackSideEffects && newFiber.alternate === null) { 2900 newFiber.effectTag = Placement; 2901 } 2902 return newFiber; 2903 } 2904 2905 function updateTextNode(returnFiber, current$$1, textContent, expirationTime) { 2906 if (current$$1 === null || current$$1.tag !== HostText) { 2907 // Insert 2908 var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); 2909 created.return = returnFiber; 2910 return created; 2911 } else { 2912 // Update 2913 var existing = useFiber(current$$1, textContent, expirationTime); 2914 existing.return = returnFiber; 2915 return existing; 2916 } 2917 } 2918 2919 function updateElement(returnFiber, current$$1, element, expirationTime) { 2920 if (current$$1 !== null && current$$1.elementType === element.type) { 2921 // Move based on index 2922 var existing = useFiber(current$$1, element.props, expirationTime); 2923 existing.ref = coerceRef(returnFiber, current$$1, element); 2924 existing.return = returnFiber; 2925 return existing; 2926 } else { 2927 // Insert 2928 var created = createFiberFromElement(element, returnFiber.mode, expirationTime); 2929 created.ref = coerceRef(returnFiber, current$$1, element); 2930 created.return = returnFiber; 2931 return created; 2932 } 2933 } 2934 2935 function updatePortal(returnFiber, current$$1, portal, expirationTime) { 2936 if (current$$1 === null || current$$1.tag !== HostPortal || current$$1.stateNode.containerInfo !== portal.containerInfo || current$$1.stateNode.implementation !== portal.implementation) { 2937 // Insert 2938 var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); 2939 created.return = returnFiber; 2940 return created; 2941 } else { 2942 // Update 2943 var existing = useFiber(current$$1, portal.children || [], expirationTime); 2944 existing.return = returnFiber; 2945 return existing; 2946 } 2947 } 2948 2949 function updateFragment(returnFiber, current$$1, fragment, expirationTime, key) { 2950 if (current$$1 === null || current$$1.tag !== Fragment) { 2951 // Insert 2952 var created = createFiberFromFragment(fragment, returnFiber.mode, expirationTime, key); 2953 created.return = returnFiber; 2954 return created; 2955 } else { 2956 // Update 2957 var existing = useFiber(current$$1, fragment, expirationTime); 2958 existing.return = returnFiber; 2959 return existing; 2960 } 2961 } 2962 2963 function createChild(returnFiber, newChild, expirationTime) { 2964 if (typeof newChild === 'string' || typeof newChild === 'number') { 2965 // Text nodes don't have keys. If the previous node is implicitly keyed 2966 // we can continue to replace it without aborting even if it is not a text 2967 // node. 2968 var created = createFiberFromText('' + newChild, returnFiber.mode, expirationTime); 2969 created.return = returnFiber; 2970 return created; 2971 } 2972 2973 if (typeof newChild === 'object' && newChild !== null) { 2974 switch (newChild.$$typeof) { 2975 case REACT_ELEMENT_TYPE: 2976 { 2977 var _created = createFiberFromElement(newChild, returnFiber.mode, expirationTime); 2978 _created.ref = coerceRef(returnFiber, null, newChild); 2979 _created.return = returnFiber; 2980 return _created; 2981 } 2982 case REACT_PORTAL_TYPE: 2983 { 2984 var _created2 = createFiberFromPortal(newChild, returnFiber.mode, expirationTime); 2985 _created2.return = returnFiber; 2986 return _created2; 2987 } 2988 } 2989 2990 if (isArray(newChild) || getIteratorFn(newChild)) { 2991 var _created3 = createFiberFromFragment(newChild, returnFiber.mode, expirationTime, null); 2992 _created3.return = returnFiber; 2993 return _created3; 2994 } 2995 2996 throwOnInvalidObjectType(returnFiber, newChild); 2997 } 2998 2999 return null; 3000 } 3001 3002 function updateSlot(returnFiber, oldFiber, newChild, expirationTime) { 3003 // Update the fiber if the keys match, otherwise return null. 3004 3005 var key = oldFiber !== null ? oldFiber.key : null; 3006 3007 if (typeof newChild === 'string' || typeof newChild === 'number') { 3008 // Text nodes don't have keys. If the previous node is implicitly keyed 3009 // we can continue to replace it without aborting even if it is not a text 3010 // node. 3011 if (key !== null) { 3012 return null; 3013 } 3014 return updateTextNode(returnFiber, oldFiber, '' + newChild, expirationTime); 3015 } 3016 3017 if (typeof newChild === 'object' && newChild !== null) { 3018 switch (newChild.$$typeof) { 3019 case REACT_ELEMENT_TYPE: 3020 { 3021 if (newChild.key === key) { 3022 if (newChild.type === REACT_FRAGMENT_TYPE) { 3023 return updateFragment(returnFiber, oldFiber, newChild.props.children, expirationTime, key); 3024 } 3025 return updateElement(returnFiber, oldFiber, newChild, expirationTime); 3026 } else { 3027 return null; 3028 } 3029 } 3030 case REACT_PORTAL_TYPE: 3031 { 3032 if (newChild.key === key) { 3033 return updatePortal(returnFiber, oldFiber, newChild, expirationTime); 3034 } else { 3035 return null; 3036 } 3037 } 3038 } 3039 3040 if (isArray(newChild) || getIteratorFn(newChild)) { 3041 if (key !== null) { 3042 return null; 3043 } 3044 3045 return updateFragment(returnFiber, oldFiber, newChild, expirationTime, null); 3046 } 3047 3048 throwOnInvalidObjectType(returnFiber, newChild); 3049 } 3050 3051 return null; 3052 } 3053 3054 function updateFromMap(existingChildren, returnFiber, newIdx, newChild, expirationTime) { 3055 if (typeof newChild === 'string' || typeof newChild === 'number') { 3056 // Text nodes don't have keys, so we neither have to check the old nor 3057 // new node for the key. If both are text nodes, they match. 3058 var matchedFiber = existingChildren.get(newIdx) || null; 3059 return updateTextNode(returnFiber, matchedFiber, '' + newChild, expirationTime); 3060 } 3061 3062 if (typeof newChild === 'object' && newChild !== null) { 3063 switch (newChild.$$typeof) { 3064 case REACT_ELEMENT_TYPE: 3065 { 3066 var _matchedFiber = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; 3067 if (newChild.type === REACT_FRAGMENT_TYPE) { 3068 return updateFragment(returnFiber, _matchedFiber, newChild.props.children, expirationTime, newChild.key); 3069 } 3070 return updateElement(returnFiber, _matchedFiber, newChild, expirationTime); 3071 } 3072 case REACT_PORTAL_TYPE: 3073 { 3074 var _matchedFiber2 = existingChildren.get(newChild.key === null ? newIdx : newChild.key) || null; 3075 return updatePortal(returnFiber, _matchedFiber2, newChild, expirationTime); 3076 } 3077 } 3078 3079 if (isArray(newChild) || getIteratorFn(newChild)) { 3080 var _matchedFiber3 = existingChildren.get(newIdx) || null; 3081 return updateFragment(returnFiber, _matchedFiber3, newChild, expirationTime, null); 3082 } 3083 3084 throwOnInvalidObjectType(returnFiber, newChild); 3085 } 3086 3087 return null; 3088 } 3089 3090 /** 3091 * Warns if there is a duplicate or missing key 3092 */ 3093 function reconcileChildrenArray(returnFiber, currentFirstChild, newChildren, expirationTime) { 3094 // This algorithm can't optimize by searching from both ends since we 3095 // don't have backpointers on fibers. I'm trying to see how far we can get 3096 // with that model. If it ends up not being worth the tradeoffs, we can 3097 // add it later. 3098 3099 // Even with a two ended optimization, we'd want to optimize for the case 3100 // where there are few changes and brute force the comparison instead of 3101 // going for the Map. It'd like to explore hitting that path first in 3102 // forward-only mode and only go for the Map once we notice that we need 3103 // lots of look ahead. This doesn't handle reversal as well as two ended 3104 // search but that's unusual. Besides, for the two ended optimization to 3105 // work on Iterables, we'd need to copy the whole set. 3106 3107 // In this first iteration, we'll just live with hitting the bad case 3108 // (adding everything to a Map) in for every insert/move. 3109 3110 // If you change this code, also update reconcileChildrenIterator() which 3111 // uses the same algorithm. 3112 3113 var resultingFirstChild = null; 3114 var previousNewFiber = null; 3115 3116 var oldFiber = currentFirstChild; 3117 var lastPlacedIndex = 0; 3118 var newIdx = 0; 3119 var nextOldFiber = null; 3120 for (; oldFiber !== null && newIdx < newChildren.length; newIdx++) { 3121 if (oldFiber.index > newIdx) { 3122 nextOldFiber = oldFiber; 3123 oldFiber = null; 3124 } else { 3125 nextOldFiber = oldFiber.sibling; 3126 } 3127 var newFiber = updateSlot(returnFiber, oldFiber, newChildren[newIdx], expirationTime); 3128 if (newFiber === null) { 3129 // TODO: This breaks on empty slots like null children. That's 3130 // unfortunate because it triggers the slow path all the time. We need 3131 // a better way to communicate whether this was a miss or null, 3132 // boolean, undefined, etc. 3133 if (oldFiber === null) { 3134 oldFiber = nextOldFiber; 3135 } 3136 break; 3137 } 3138 if (shouldTrackSideEffects) { 3139 if (oldFiber && newFiber.alternate === null) { 3140 // We matched the slot, but we didn't reuse the existing fiber, so we 3141 // need to delete the existing child. 3142 deleteChild(returnFiber, oldFiber); 3143 } 3144 } 3145 lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); 3146 if (previousNewFiber === null) { 3147 // TODO: Move out of the loop. This only happens for the first run. 3148 resultingFirstChild = newFiber; 3149 } else { 3150 // TODO: Defer siblings if we're not at the right index for this slot. 3151 // I.e. if we had null values before, then we want to defer this 3152 // for each null value. However, we also don't want to call updateSlot 3153 // with the previous one. 3154 previousNewFiber.sibling = newFiber; 3155 } 3156 previousNewFiber = newFiber; 3157 oldFiber = nextOldFiber; 3158 } 3159 3160 if (newIdx === newChildren.length) { 3161 // We've reached the end of the new children. We can delete the rest. 3162 deleteRemainingChildren(returnFiber, oldFiber); 3163 return resultingFirstChild; 3164 } 3165 3166 if (oldFiber === null) { 3167 // If we don't have any more existing children we can choose a fast path 3168 // since the rest will all be insertions. 3169 for (; newIdx < newChildren.length; newIdx++) { 3170 var _newFiber = createChild(returnFiber, newChildren[newIdx], expirationTime); 3171 if (!_newFiber) { 3172 continue; 3173 } 3174 lastPlacedIndex = placeChild(_newFiber, lastPlacedIndex, newIdx); 3175 if (previousNewFiber === null) { 3176 // TODO: Move out of the loop. This only happens for the first run. 3177 resultingFirstChild = _newFiber; 3178 } else { 3179 previousNewFiber.sibling = _newFiber; 3180 } 3181 previousNewFiber = _newFiber; 3182 } 3183 return resultingFirstChild; 3184 } 3185 3186 // Add all children to a key map for quick lookups. 3187 var existingChildren = mapRemainingChildren(returnFiber, oldFiber); 3188 3189 // Keep scanning and use the map to restore deleted items as moves. 3190 for (; newIdx < newChildren.length; newIdx++) { 3191 var _newFiber2 = updateFromMap(existingChildren, returnFiber, newIdx, newChildren[newIdx], expirationTime); 3192 if (_newFiber2) { 3193 if (shouldTrackSideEffects) { 3194 if (_newFiber2.alternate !== null) { 3195 // The new fiber is a work in progress, but if there exists a 3196 // current, that means that we reused the fiber. We need to delete 3197 // it from the child list so that we don't add it to the deletion 3198 // list. 3199 existingChildren.delete(_newFiber2.key === null ? newIdx : _newFiber2.key); 3200 } 3201 } 3202 lastPlacedIndex = placeChild(_newFiber2, lastPlacedIndex, newIdx); 3203 if (previousNewFiber === null) { 3204 resultingFirstChild = _newFiber2; 3205 } else { 3206 previousNewFiber.sibling = _newFiber2; 3207 } 3208 previousNewFiber = _newFiber2; 3209 } 3210 } 3211 3212 if (shouldTrackSideEffects) { 3213 // Any existing children that weren't consumed above were deleted. We need 3214 // to add them to the deletion list. 3215 existingChildren.forEach(function (child) { 3216 return deleteChild(returnFiber, child); 3217 }); 3218 } 3219 3220 return resultingFirstChild; 3221 } 3222 3223 function reconcileChildrenIterator(returnFiber, currentFirstChild, newChildrenIterable, expirationTime) { 3224 // This is the same implementation as reconcileChildrenArray(), 3225 // but using the iterator instead. 3226 3227 var iteratorFn = getIteratorFn(newChildrenIterable); 3228 !(typeof iteratorFn === 'function') ? reactProdInvariant('150') : void 0; 3229 3230 var newChildren = iteratorFn.call(newChildrenIterable); 3231 !(newChildren != null) ? reactProdInvariant('151') : void 0; 3232 3233 var resultingFirstChild = null; 3234 var previousNewFiber = null; 3235 3236 var oldFiber = currentFirstChild; 3237 var lastPlacedIndex = 0; 3238 var newIdx = 0; 3239 var nextOldFiber = null; 3240 3241 var step = newChildren.next(); 3242 for (; oldFiber !== null && !step.done; newIdx++, step = newChildren.next()) { 3243 if (oldFiber.index > newIdx) { 3244 nextOldFiber = oldFiber; 3245 oldFiber = null; 3246 } else { 3247 nextOldFiber = oldFiber.sibling; 3248 } 3249 var newFiber = updateSlot(returnFiber, oldFiber, step.value, expirationTime); 3250 if (newFiber === null) { 3251 // TODO: This breaks on empty slots like null children. That's 3252 // unfortunate because it triggers the slow path all the time. We need 3253 // a better way to communicate whether this was a miss or null, 3254 // boolean, undefined, etc. 3255 if (!oldFiber) { 3256 oldFiber = nextOldFiber; 3257 } 3258 break; 3259 } 3260 if (shouldTrackSideEffects) { 3261 if (oldFiber && newFiber.alternate === null) { 3262 // We matched the slot, but we didn't reuse the existing fiber, so we 3263 // need to delete the existing child. 3264 deleteChild(returnFiber, oldFiber); 3265 } 3266 } 3267 lastPlacedIndex = placeChild(newFiber, lastPlacedIndex, newIdx); 3268 if (previousNewFiber === null) { 3269 // TODO: Move out of the loop. This only happens for the first run. 3270 resultingFirstChild = newFiber; 3271 } else { 3272 // TODO: Defer siblings if we're not at the right index for this slot. 3273 // I.e. if we had null values before, then we want to defer this 3274 // for each null value. However, we also don't want to call updateSlot 3275 // with the previous one. 3276 previousNewFiber.sibling = newFiber; 3277 } 3278 previousNewFiber = newFiber; 3279 oldFiber = nextOldFiber; 3280 } 3281 3282 if (step.done) { 3283 // We've reached the end of the new children. We can delete the rest. 3284 deleteRemainingChildren(returnFiber, oldFiber); 3285 return resultingFirstChild; 3286 } 3287 3288 if (oldFiber === null) { 3289 // If we don't have any more existing children we can choose a fast path 3290 // since the rest will all be insertions. 3291 for (; !step.done; newIdx++, step = newChildren.next()) { 3292 var _newFiber3 = createChild(returnFiber, step.value, expirationTime); 3293 if (_newFiber3 === null) { 3294 continue; 3295 } 3296 lastPlacedIndex = placeChild(_newFiber3, lastPlacedIndex, newIdx); 3297 if (previousNewFiber === null) { 3298 // TODO: Move out of the loop. This only happens for the first run. 3299 resultingFirstChild = _newFiber3; 3300 } else { 3301 previousNewFiber.sibling = _newFiber3; 3302 } 3303 previousNewFiber = _newFiber3; 3304 } 3305 return resultingFirstChild; 3306 } 3307 3308 // Add all children to a key map for quick lookups. 3309 var existingChildren = mapRemainingChildren(returnFiber, oldFiber); 3310 3311 // Keep scanning and use the map to restore deleted items as moves. 3312 for (; !step.done; newIdx++, step = newChildren.next()) { 3313 var _newFiber4 = updateFromMap(existingChildren, returnFiber, newIdx, step.value, expirationTime); 3314 if (_newFiber4 !== null) { 3315 if (shouldTrackSideEffects) { 3316 if (_newFiber4.alternate !== null) { 3317 // The new fiber is a work in progress, but if there exists a 3318 // current, that means that we reused the fiber. We need to delete 3319 // it from the child list so that we don't add it to the deletion 3320 // list. 3321 existingChildren.delete(_newFiber4.key === null ? newIdx : _newFiber4.key); 3322 } 3323 } 3324 lastPlacedIndex = placeChild(_newFiber4, lastPlacedIndex, newIdx); 3325 if (previousNewFiber === null) { 3326 resultingFirstChild = _newFiber4; 3327 } else { 3328 previousNewFiber.sibling = _newFiber4; 3329 } 3330 previousNewFiber = _newFiber4; 3331 } 3332 } 3333 3334 if (shouldTrackSideEffects) { 3335 // Any existing children that weren't consumed above were deleted. We need 3336 // to add them to the deletion list. 3337 existingChildren.forEach(function (child) { 3338 return deleteChild(returnFiber, child); 3339 }); 3340 } 3341 3342 return resultingFirstChild; 3343 } 3344 3345 function reconcileSingleTextNode(returnFiber, currentFirstChild, textContent, expirationTime) { 3346 // There's no need to check for keys on text nodes since we don't have a 3347 // way to define them. 3348 if (currentFirstChild !== null && currentFirstChild.tag === HostText) { 3349 // We already have an existing node so let's just update it and delete 3350 // the rest. 3351 deleteRemainingChildren(returnFiber, currentFirstChild.sibling); 3352 var existing = useFiber(currentFirstChild, textContent, expirationTime); 3353 existing.return = returnFiber; 3354 return existing; 3355 } 3356 // The existing first child is not a text node so we need to create one 3357 // and delete the existing ones. 3358 deleteRemainingChildren(returnFiber, currentFirstChild); 3359 var created = createFiberFromText(textContent, returnFiber.mode, expirationTime); 3360 created.return = returnFiber; 3361 return created; 3362 } 3363 3364 function reconcileSingleElement(returnFiber, currentFirstChild, element, expirationTime) { 3365 var key = element.key; 3366 var child = currentFirstChild; 3367 while (child !== null) { 3368 // TODO: If key === null and child.key === null, then this only applies to 3369 // the first item in the list. 3370 if (child.key === key) { 3371 if (child.tag === Fragment ? element.type === REACT_FRAGMENT_TYPE : child.elementType === element.type) { 3372 deleteRemainingChildren(returnFiber, child.sibling); 3373 var existing = useFiber(child, element.type === REACT_FRAGMENT_TYPE ? element.props.children : element.props, expirationTime); 3374 existing.ref = coerceRef(returnFiber, child, element); 3375 existing.return = returnFiber; 3376 return existing; 3377 } else { 3378 deleteRemainingChildren(returnFiber, child); 3379 break; 3380 } 3381 } else { 3382 deleteChild(returnFiber, child); 3383 } 3384 child = child.sibling; 3385 } 3386 3387 if (element.type === REACT_FRAGMENT_TYPE) { 3388 var created = createFiberFromFragment(element.props.children, returnFiber.mode, expirationTime, element.key); 3389 created.return = returnFiber; 3390 return created; 3391 } else { 3392 var _created4 = createFiberFromElement(element, returnFiber.mode, expirationTime); 3393 _created4.ref = coerceRef(returnFiber, currentFirstChild, element); 3394 _created4.return = returnFiber; 3395 return _created4; 3396 } 3397 } 3398 3399 function reconcileSinglePortal(returnFiber, currentFirstChild, portal, expirationTime) { 3400 var key = portal.key; 3401 var child = currentFirstChild; 3402 while (child !== null) { 3403 // TODO: If key === null and child.key === null, then this only applies to 3404 // the first item in the list. 3405 if (child.key === key) { 3406 if (child.tag === HostPortal && child.stateNode.containerInfo === portal.containerInfo && child.stateNode.implementation === portal.implementation) { 3407 deleteRemainingChildren(returnFiber, child.sibling); 3408 var existing = useFiber(child, portal.children || [], expirationTime); 3409 existing.return = returnFiber; 3410 return existing; 3411 } else { 3412 deleteRemainingChildren(returnFiber, child); 3413 break; 3414 } 3415 } else { 3416 deleteChild(returnFiber, child); 3417 } 3418 child = child.sibling; 3419 } 3420 3421 var created = createFiberFromPortal(portal, returnFiber.mode, expirationTime); 3422 created.return = returnFiber; 3423 return created; 3424 } 3425 3426 // This API will tag the children with the side-effect of the reconciliation 3427 // itself. They will be added to the side-effect list as we pass through the 3428 // children and the parent. 3429 function reconcileChildFibers(returnFiber, currentFirstChild, newChild, expirationTime) { 3430 // This function is not recursive. 3431 // If the top level item is an array, we treat it as a set of children, 3432 // not as a fragment. Nested arrays on the other hand will be treated as 3433 // fragment nodes. Recursion happens at the normal flow. 3434 3435 // Handle top level unkeyed fragments as if they were arrays. 3436 // This leads to an ambiguity between <>{[...]}</> and <>...</>. 3437 // We treat the ambiguous cases above the same. 3438 var isUnkeyedTopLevelFragment = typeof newChild === 'object' && newChild !== null && newChild.type === REACT_FRAGMENT_TYPE && newChild.key === null; 3439 if (isUnkeyedTopLevelFragment) { 3440 newChild = newChild.props.children; 3441 } 3442 3443 // Handle object types 3444 var isObject = typeof newChild === 'object' && newChild !== null; 3445 3446 if (isObject) { 3447 switch (newChild.$$typeof) { 3448 case REACT_ELEMENT_TYPE: 3449 return placeSingleChild(reconcileSingleElement(returnFiber, currentFirstChild, newChild, expirationTime)); 3450 case REACT_PORTAL_TYPE: 3451 return placeSingleChild(reconcileSinglePortal(returnFiber, currentFirstChild, newChild, expirationTime)); 3452 } 3453 } 3454 3455 if (typeof newChild === 'string' || typeof newChild === 'number') { 3456 return placeSingleChild(reconcileSingleTextNode(returnFiber, currentFirstChild, '' + newChild, expirationTime)); 3457 } 3458 3459 if (isArray(newChild)) { 3460 return reconcileChildrenArray(returnFiber, currentFirstChild, newChild, expirationTime); 3461 } 3462 3463 if (getIteratorFn(newChild)) { 3464 return reconcileChildrenIterator(returnFiber, currentFirstChild, newChild, expirationTime); 3465 } 3466 3467 if (isObject) { 3468 throwOnInvalidObjectType(returnFiber, newChild); 3469 } 3470 3471 if (typeof newChild === 'undefined' && !isUnkeyedTopLevelFragment) { 3472 // If the new child is undefined, and the return fiber is a composite 3473 // component, throw an error. If Fiber return types are disabled, 3474 // we already threw above. 3475 switch (returnFiber.tag) { 3476 case ClassComponent: 3477 { 3478 3479 } 3480 // Intentionally fall through to the next case, which handles both 3481 // functions and classes 3482 // eslint-disable-next-lined no-fallthrough 3483 case FunctionComponent: 3484 { 3485 var Component = returnFiber.type; 3486 reactProdInvariant('152', Component.displayName || Component.name || 'Component'); 3487 } 3488 } 3489 } 3490 3491 // Remaining cases are all treated as empty. 3492 return deleteRemainingChildren(returnFiber, currentFirstChild); 3493 } 3494 3495 return reconcileChildFibers; 3496 } 3497 3498 var reconcileChildFibers = ChildReconciler(true); 3499 var mountChildFibers = ChildReconciler(false); 3500 3501 function cloneChildFibers(current$$1, workInProgress) { 3502 !(current$$1 === null || workInProgress.child === current$$1.child) ? reactProdInvariant('153') : void 0; 3503 3504 if (workInProgress.child === null) { 3505 return; 3506 } 3507 3508 var currentChild = workInProgress.child; 3509 var newChild = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); 3510 workInProgress.child = newChild; 3511 3512 newChild.return = workInProgress; 3513 while (currentChild.sibling !== null) { 3514 currentChild = currentChild.sibling; 3515 newChild = newChild.sibling = createWorkInProgress(currentChild, currentChild.pendingProps, currentChild.expirationTime); 3516 newChild.return = workInProgress; 3517 } 3518 newChild.sibling = null; 3519 } 3520 3521 var NO_CONTEXT$1 = {}; 3522 3523 var contextStackCursor$1 = createCursor(NO_CONTEXT$1); 3524 var contextFiberStackCursor = createCursor(NO_CONTEXT$1); 3525 var rootInstanceStackCursor = createCursor(NO_CONTEXT$1); 3526 3527 function requiredContext(c) { 3528 !(c !== NO_CONTEXT$1) ? reactProdInvariant('174') : void 0; 3529 return c; 3530 } 3531 3532 function getRootHostContainer() { 3533 var rootInstance = requiredContext(rootInstanceStackCursor.current); 3534 return rootInstance; 3535 } 3536 3537 function pushHostContainer(fiber, nextRootInstance) { 3538 // Push current root instance onto the stack; 3539 // This allows us to reset root when portals are popped. 3540 push(rootInstanceStackCursor, nextRootInstance, fiber); 3541 // Track the context and the Fiber that provided it. 3542 // This enables us to pop only Fibers that provide unique contexts. 3543 push(contextFiberStackCursor, fiber, fiber); 3544 3545 // Finally, we need to push the host context to the stack. 3546 // However, we can't just call getRootHostContext() and push it because 3547 // we'd have a different number of entries on the stack depending on 3548 // whether getRootHostContext() throws somewhere in renderer code or not. 3549 // So we push an empty value first. This lets us safely unwind on errors. 3550 push(contextStackCursor$1, NO_CONTEXT$1, fiber); 3551 var nextRootContext = getRootHostContext(nextRootInstance); 3552 // Now that we know this function doesn't throw, replace it. 3553 pop(contextStackCursor$1, fiber); 3554 push(contextStackCursor$1, nextRootContext, fiber); 3555 } 3556 3557 function popHostContainer(fiber) { 3558 pop(contextStackCursor$1, fiber); 3559 pop(contextFiberStackCursor, fiber); 3560 pop(rootInstanceStackCursor, fiber); 3561 } 3562 3563 function getHostContext() { 3564 var context = requiredContext(contextStackCursor$1.current); 3565 return context; 3566 } 3567 3568 function pushHostContext(fiber) { 3569 var rootInstance = requiredContext(rootInstanceStackCursor.current); 3570 var context = requiredContext(contextStackCursor$1.current); 3571 var nextContext = getChildHostContext(context, fiber.type, rootInstance); 3572 3573 // Don't push this Fiber's context unless it's unique. 3574 if (context === nextContext) { 3575 return; 3576 } 3577 3578 // Track the context and the Fiber that provided it. 3579 // This enables us to pop only Fibers that provide unique contexts. 3580 push(contextFiberStackCursor, fiber, fiber); 3581 push(contextStackCursor$1, nextContext, fiber); 3582 } 3583 3584 function popHostContext(fiber) { 3585 // Do not pop unless this Fiber provided the current context. 3586 // pushHostContext() only pushes Fibers that provide unique contexts. 3587 if (contextFiberStackCursor.current !== fiber) { 3588 return; 3589 } 3590 3591 pop(contextStackCursor$1, fiber); 3592 pop(contextFiberStackCursor, fiber); 3593 } 3594 3595 var NoEffect$1 = /* */0; 3596 var UnmountSnapshot = /* */2; 3597 var UnmountMutation = /* */4; 3598 var MountMutation = /* */8; 3599 var UnmountLayout = /* */16; 3600 var MountLayout = /* */32; 3601 var MountPassive = /* */64; 3602 var UnmountPassive = /* */128; 3603 3604 var ReactCurrentDispatcher$1 = ReactSharedInternals.ReactCurrentDispatcher; 3605 3606 3607 // These are set right before calling the component. 3608 var renderExpirationTime = NoWork; 3609 // The work-in-progress fiber. I've named it differently to distinguish it from 3610 // the work-in-progress hook. 3611 var currentlyRenderingFiber$1 = null; 3612 3613 // Hooks are stored as a linked list on the fiber's memoizedState field. The 3614 // current hook list is the list that belongs to the current fiber. The 3615 // work-in-progress hook list is a new list that will be added to the 3616 // work-in-progress fiber. 3617 var currentHook = null; 3618 var nextCurrentHook = null; 3619 var firstWorkInProgressHook = null; 3620 var workInProgressHook = null; 3621 var nextWorkInProgressHook = null; 3622 3623 var remainingExpirationTime = NoWork; 3624 var componentUpdateQueue = null; 3625 var sideEffectTag = 0; 3626 3627 // Updates scheduled during render will trigger an immediate re-render at the 3628 // end of the current pass. We can't store these updates on the normal queue, 3629 // because if the work is aborted, they should be discarded. Because this is 3630 // a relatively rare case, we also don't want to add an additional field to 3631 // either the hook or queue object types. So we store them in a lazily create 3632 // map of queue -> render-phase updates, which are discarded once the component 3633 // completes without re-rendering. 3634 3635 // Whether an update was scheduled during the currently executing render pass. 3636 var didScheduleRenderPhaseUpdate = false; 3637 // Lazily created map of render-phase updates 3638 var renderPhaseUpdates = null; 3639 // Counter to prevent infinite loops. 3640 var numberOfReRenders = 0; 3641 var RE_RENDER_LIMIT = 25; 3642 3643 function throwInvalidHookError() { 3644 reactProdInvariant('321'); 3645 } 3646 3647 function areHookInputsEqual(nextDeps, prevDeps) { 3648 if (prevDeps === null) { 3649 return false; 3650 } 3651 3652 for (var i = 0; i < prevDeps.length && i < nextDeps.length; i++) { 3653 if (is(nextDeps[i], prevDeps[i])) { 3654 continue; 3655 } 3656 return false; 3657 } 3658 return true; 3659 } 3660 3661 function renderWithHooks(current, workInProgress, Component, props, refOrContext, nextRenderExpirationTime) { 3662 renderExpirationTime = nextRenderExpirationTime; 3663 currentlyRenderingFiber$1 = workInProgress; 3664 nextCurrentHook = current !== null ? current.memoizedState : null; 3665 3666 { 3667 ReactCurrentDispatcher$1.current = nextCurrentHook === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; 3668 } 3669 3670 var children = Component(props, refOrContext); 3671 3672 if (didScheduleRenderPhaseUpdate) { 3673 do { 3674 didScheduleRenderPhaseUpdate = false; 3675 numberOfReRenders += 1; 3676 3677 // Start over from the beginning of the list 3678 nextCurrentHook = current !== null ? current.memoizedState : null; 3679 nextWorkInProgressHook = firstWorkInProgressHook; 3680 3681 currentHook = null; 3682 workInProgressHook = null; 3683 componentUpdateQueue = null; 3684 3685 ReactCurrentDispatcher$1.current = HooksDispatcherOnUpdate; 3686 3687 children = Component(props, refOrContext); 3688 } while (didScheduleRenderPhaseUpdate); 3689 3690 renderPhaseUpdates = null; 3691 numberOfReRenders = 0; 3692 } 3693 3694 // We can assume the previous dispatcher is always this one, since we set it 3695 // at the beginning of the render phase and there's no re-entrancy. 3696 ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; 3697 3698 var renderedWork = currentlyRenderingFiber$1; 3699 3700 renderedWork.memoizedState = firstWorkInProgressHook; 3701 renderedWork.expirationTime = remainingExpirationTime; 3702 renderedWork.updateQueue = componentUpdateQueue; 3703 renderedWork.effectTag |= sideEffectTag; 3704 3705 var didRenderTooFewHooks = currentHook !== null && currentHook.next !== null; 3706 3707 renderExpirationTime = NoWork; 3708 currentlyRenderingFiber$1 = null; 3709 3710 currentHook = null; 3711 nextCurrentHook = null; 3712 firstWorkInProgressHook = null; 3713 workInProgressHook = null; 3714 nextWorkInProgressHook = null; 3715 3716 remainingExpirationTime = NoWork; 3717 componentUpdateQueue = null; 3718 sideEffectTag = 0; 3719 3720 // These were reset above 3721 // didScheduleRenderPhaseUpdate = false; 3722 // renderPhaseUpdates = null; 3723 // numberOfReRenders = 0; 3724 3725 !!didRenderTooFewHooks ? reactProdInvariant('300') : void 0; 3726 3727 return children; 3728 } 3729 3730 function bailoutHooks(current, workInProgress, expirationTime) { 3731 workInProgress.updateQueue = current.updateQueue; 3732 workInProgress.effectTag &= ~(Passive | Update); 3733 if (current.expirationTime <= expirationTime) { 3734 current.expirationTime = NoWork; 3735 } 3736 } 3737 3738 function resetHooks() { 3739 // We can assume the previous dispatcher is always this one, since we set it 3740 // at the beginning of the render phase and there's no re-entrancy. 3741 ReactCurrentDispatcher$1.current = ContextOnlyDispatcher; 3742 3743 // This is used to reset the state of this module when a component throws. 3744 // It's also called inside mountIndeterminateComponent if we determine the 3745 // component is a module-style component. 3746 renderExpirationTime = NoWork; 3747 currentlyRenderingFiber$1 = null; 3748 3749 currentHook = null; 3750 nextCurrentHook = null; 3751 firstWorkInProgressHook = null; 3752 workInProgressHook = null; 3753 nextWorkInProgressHook = null; 3754 3755 remainingExpirationTime = NoWork; 3756 componentUpdateQueue = null; 3757 sideEffectTag = 0; 3758 3759 didScheduleRenderPhaseUpdate = false; 3760 renderPhaseUpdates = null; 3761 numberOfReRenders = 0; 3762 } 3763 3764 function mountWorkInProgressHook() { 3765 var hook = { 3766 memoizedState: null, 3767 3768 baseState: null, 3769 queue: null, 3770 baseUpdate: null, 3771 3772 next: null 3773 }; 3774 3775 if (workInProgressHook === null) { 3776 // This is the first hook in the list 3777 firstWorkInProgressHook = workInProgressHook = hook; 3778 } else { 3779 // Append to the end of the list 3780 workInProgressHook = workInProgressHook.next = hook; 3781 } 3782 return workInProgressHook; 3783 } 3784 3785 function updateWorkInProgressHook() { 3786 // This function is used both for updates and for re-renders triggered by a 3787 // render phase update. It assumes there is either a current hook we can 3788 // clone, or a work-in-progress hook from a previous render pass that we can 3789 // use as a base. When we reach the end of the base list, we must switch to 3790 // the dispatcher used for mounts. 3791 if (nextWorkInProgressHook !== null) { 3792 // There's already a work-in-progress. Reuse it. 3793 workInProgressHook = nextWorkInProgressHook; 3794 nextWorkInProgressHook = workInProgressHook.next; 3795 3796 currentHook = nextCurrentHook; 3797 nextCurrentHook = currentHook !== null ? currentHook.next : null; 3798 } else { 3799 // Clone from the current hook. 3800 !(nextCurrentHook !== null) ? reactProdInvariant('310') : void 0; 3801 currentHook = nextCurrentHook; 3802 3803 var newHook = { 3804 memoizedState: currentHook.memoizedState, 3805 3806 baseState: currentHook.baseState, 3807 queue: currentHook.queue, 3808 baseUpdate: currentHook.baseUpdate, 3809 3810 next: null 3811 }; 3812 3813 if (workInProgressHook === null) { 3814 // This is the first hook in the list. 3815 workInProgressHook = firstWorkInProgressHook = newHook; 3816 } else { 3817 // Append to the end of the list. 3818 workInProgressHook = workInProgressHook.next = newHook; 3819 } 3820 nextCurrentHook = currentHook.next; 3821 } 3822 return workInProgressHook; 3823 } 3824 3825 function createFunctionComponentUpdateQueue() { 3826 return { 3827 lastEffect: null 3828 }; 3829 } 3830 3831 function basicStateReducer(state, action) { 3832 return typeof action === 'function' ? action(state) : action; 3833 } 3834 3835 function mountReducer(reducer, initialArg, init) { 3836 var hook = mountWorkInProgressHook(); 3837 var initialState = void 0; 3838 if (init !== undefined) { 3839 initialState = init(initialArg); 3840 } else { 3841 initialState = initialArg; 3842 } 3843 hook.memoizedState = hook.baseState = initialState; 3844 var queue = hook.queue = { 3845 last: null, 3846 dispatch: null, 3847 lastRenderedReducer: reducer, 3848 lastRenderedState: initialState 3849 }; 3850 var dispatch = queue.dispatch = dispatchAction.bind(null, 3851 // Flow doesn't know this is non-null, but we do. 3852 currentlyRenderingFiber$1, queue); 3853 return [hook.memoizedState, dispatch]; 3854 } 3855 3856 function updateReducer(reducer, initialArg, init) { 3857 var hook = updateWorkInProgressHook(); 3858 var queue = hook.queue; 3859 !(queue !== null) ? reactProdInvariant('311') : void 0; 3860 3861 queue.lastRenderedReducer = reducer; 3862 3863 if (numberOfReRenders > 0) { 3864 // This is a re-render. Apply the new render phase updates to the previous 3865 var _dispatch = queue.dispatch; 3866 if (renderPhaseUpdates !== null) { 3867 // Render phase updates are stored in a map of queue -> linked list 3868 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); 3869 if (firstRenderPhaseUpdate !== undefined) { 3870 renderPhaseUpdates.delete(queue); 3871 var newState = hook.memoizedState; 3872 var update = firstRenderPhaseUpdate; 3873 do { 3874 // Process this render phase update. We don't have to check the 3875 // priority because it will always be the same as the current 3876 // render's. 3877 var _action = update.action; 3878 newState = reducer(newState, _action); 3879 update = update.next; 3880 } while (update !== null); 3881 3882 // Mark that the fiber performed work, but only if the new state is 3883 // different from the current state. 3884 if (!is(newState, hook.memoizedState)) { 3885 markWorkInProgressReceivedUpdate(); 3886 } 3887 3888 hook.memoizedState = newState; 3889 // Don't persist the state accumlated from the render phase updates to 3890 // the base state unless the queue is empty. 3891 // TODO: Not sure if this is the desired semantics, but it's what we 3892 // do for gDSFP. I can't remember why. 3893 if (hook.baseUpdate === queue.last) { 3894 hook.baseState = newState; 3895 } 3896 3897 queue.lastRenderedState = newState; 3898 3899 return [newState, _dispatch]; 3900 } 3901 } 3902 return [hook.memoizedState, _dispatch]; 3903 } 3904 3905 // The last update in the entire queue 3906 var last = queue.last; 3907 // The last update that is part of the base state. 3908 var baseUpdate = hook.baseUpdate; 3909 var baseState = hook.baseState; 3910 3911 // Find the first unprocessed update. 3912 var first = void 0; 3913 if (baseUpdate !== null) { 3914 if (last !== null) { 3915 // For the first update, the queue is a circular linked list where 3916 // `queue.last.next = queue.first`. Once the first update commits, and 3917 // the `baseUpdate` is no longer empty, we can unravel the list. 3918 last.next = null; 3919 } 3920 first = baseUpdate.next; 3921 } else { 3922 first = last !== null ? last.next : null; 3923 } 3924 if (first !== null) { 3925 var _newState = baseState; 3926 var newBaseState = null; 3927 var newBaseUpdate = null; 3928 var prevUpdate = baseUpdate; 3929 var _update = first; 3930 var didSkip = false; 3931 do { 3932 var updateExpirationTime = _update.expirationTime; 3933 if (updateExpirationTime < renderExpirationTime) { 3934 // Priority is insufficient. Skip this update. If this is the first 3935 // skipped update, the previous update/state is the new base 3936 // update/state. 3937 if (!didSkip) { 3938 didSkip = true; 3939 newBaseUpdate = prevUpdate; 3940 newBaseState = _newState; 3941 } 3942 // Update the remaining priority in the queue. 3943 if (updateExpirationTime > remainingExpirationTime) { 3944 remainingExpirationTime = updateExpirationTime; 3945 } 3946 } else { 3947 // Process this update. 3948 if (_update.eagerReducer === reducer) { 3949 // If this update was processed eagerly, and its reducer matches the 3950 // current reducer, we can use the eagerly computed state. 3951 _newState = _update.eagerState; 3952 } else { 3953 var _action2 = _update.action; 3954 _newState = reducer(_newState, _action2); 3955 } 3956 } 3957 prevUpdate = _update; 3958 _update = _update.next; 3959 } while (_update !== null && _update !== first); 3960 3961 if (!didSkip) { 3962 newBaseUpdate = prevUpdate; 3963 newBaseState = _newState; 3964 } 3965 3966 // Mark that the fiber performed work, but only if the new state is 3967 // different from the current state. 3968 if (!is(_newState, hook.memoizedState)) { 3969 markWorkInProgressReceivedUpdate(); 3970 } 3971 3972 hook.memoizedState = _newState; 3973 hook.baseUpdate = newBaseUpdate; 3974 hook.baseState = newBaseState; 3975 3976 queue.lastRenderedState = _newState; 3977 } 3978 3979 var dispatch = queue.dispatch; 3980 return [hook.memoizedState, dispatch]; 3981 } 3982 3983 function mountState(initialState) { 3984 var hook = mountWorkInProgressHook(); 3985 if (typeof initialState === 'function') { 3986 initialState = initialState(); 3987 } 3988 hook.memoizedState = hook.baseState = initialState; 3989 var queue = hook.queue = { 3990 last: null, 3991 dispatch: null, 3992 lastRenderedReducer: basicStateReducer, 3993 lastRenderedState: initialState 3994 }; 3995 var dispatch = queue.dispatch = dispatchAction.bind(null, 3996 // Flow doesn't know this is non-null, but we do. 3997 currentlyRenderingFiber$1, queue); 3998 return [hook.memoizedState, dispatch]; 3999 } 4000 4001 function updateState(initialState) { 4002 return updateReducer(basicStateReducer, initialState); 4003 } 4004 4005 function pushEffect(tag, create, destroy, deps) { 4006 var effect = { 4007 tag: tag, 4008 create: create, 4009 destroy: destroy, 4010 deps: deps, 4011 // Circular 4012 next: null 4013 }; 4014 if (componentUpdateQueue === null) { 4015 componentUpdateQueue = createFunctionComponentUpdateQueue(); 4016 componentUpdateQueue.lastEffect = effect.next = effect; 4017 } else { 4018 var _lastEffect = componentUpdateQueue.lastEffect; 4019 if (_lastEffect === null) { 4020 componentUpdateQueue.lastEffect = effect.next = effect; 4021 } else { 4022 var firstEffect = _lastEffect.next; 4023 _lastEffect.next = effect; 4024 effect.next = firstEffect; 4025 componentUpdateQueue.lastEffect = effect; 4026 } 4027 } 4028 return effect; 4029 } 4030 4031 function mountRef(initialValue) { 4032 var hook = mountWorkInProgressHook(); 4033 var ref = { current: initialValue }; 4034 hook.memoizedState = ref; 4035 return ref; 4036 } 4037 4038 function updateRef(initialValue) { 4039 var hook = updateWorkInProgressHook(); 4040 return hook.memoizedState; 4041 } 4042 4043 function mountEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { 4044 var hook = mountWorkInProgressHook(); 4045 var nextDeps = deps === undefined ? null : deps; 4046 sideEffectTag |= fiberEffectTag; 4047 hook.memoizedState = pushEffect(hookEffectTag, create, undefined, nextDeps); 4048 } 4049 4050 function updateEffectImpl(fiberEffectTag, hookEffectTag, create, deps) { 4051 var hook = updateWorkInProgressHook(); 4052 var nextDeps = deps === undefined ? null : deps; 4053 var destroy = undefined; 4054 4055 if (currentHook !== null) { 4056 var prevEffect = currentHook.memoizedState; 4057 destroy = prevEffect.destroy; 4058 if (nextDeps !== null) { 4059 var prevDeps = prevEffect.deps; 4060 if (areHookInputsEqual(nextDeps, prevDeps)) { 4061 pushEffect(NoEffect$1, create, destroy, nextDeps); 4062 return; 4063 } 4064 } 4065 } 4066 4067 sideEffectTag |= fiberEffectTag; 4068 hook.memoizedState = pushEffect(hookEffectTag, create, destroy, nextDeps); 4069 } 4070 4071 function mountEffect(create, deps) { 4072 return mountEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); 4073 } 4074 4075 function updateEffect(create, deps) { 4076 return updateEffectImpl(Update | Passive, UnmountPassive | MountPassive, create, deps); 4077 } 4078 4079 function mountLayoutEffect(create, deps) { 4080 return mountEffectImpl(Update, UnmountMutation | MountLayout, create, deps); 4081 } 4082 4083 function updateLayoutEffect(create, deps) { 4084 return updateEffectImpl(Update, UnmountMutation | MountLayout, create, deps); 4085 } 4086 4087 function imperativeHandleEffect(create, ref) { 4088 if (typeof ref === 'function') { 4089 var refCallback = ref; 4090 var _inst = create(); 4091 refCallback(_inst); 4092 return function () { 4093 refCallback(null); 4094 }; 4095 } else if (ref !== null && ref !== undefined) { 4096 var refObject = ref; 4097 var _inst2 = create(); 4098 refObject.current = _inst2; 4099 return function () { 4100 refObject.current = null; 4101 }; 4102 } 4103 } 4104 4105 function mountImperativeHandle(ref, create, deps) { 4106 var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; 4107 4108 return mountEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); 4109 } 4110 4111 function updateImperativeHandle(ref, create, deps) { 4112 var effectDeps = deps !== null && deps !== undefined ? deps.concat([ref]) : null; 4113 4114 return updateEffectImpl(Update, UnmountMutation | MountLayout, imperativeHandleEffect.bind(null, create, ref), effectDeps); 4115 } 4116 4117 function mountDebugValue(value, formatterFn) { 4118 // This hook is normally a no-op. 4119 // The react-debug-hooks package injects its own implementation 4120 // so that e.g. DevTools can display custom hook values. 4121 } 4122 4123 var updateDebugValue = mountDebugValue; 4124 4125 function mountCallback(callback, deps) { 4126 var hook = mountWorkInProgressHook(); 4127 var nextDeps = deps === undefined ? null : deps; 4128 hook.memoizedState = [callback, nextDeps]; 4129 return callback; 4130 } 4131 4132 function updateCallback(callback, deps) { 4133 var hook = updateWorkInProgressHook(); 4134 var nextDeps = deps === undefined ? null : deps; 4135 var prevState = hook.memoizedState; 4136 if (prevState !== null) { 4137 if (nextDeps !== null) { 4138 var prevDeps = prevState[1]; 4139 if (areHookInputsEqual(nextDeps, prevDeps)) { 4140 return prevState[0]; 4141 } 4142 } 4143 } 4144 hook.memoizedState = [callback, nextDeps]; 4145 return callback; 4146 } 4147 4148 function mountMemo(nextCreate, deps) { 4149 var hook = mountWorkInProgressHook(); 4150 var nextDeps = deps === undefined ? null : deps; 4151 var nextValue = nextCreate(); 4152 hook.memoizedState = [nextValue, nextDeps]; 4153 return nextValue; 4154 } 4155 4156 function updateMemo(nextCreate, deps) { 4157 var hook = updateWorkInProgressHook(); 4158 var nextDeps = deps === undefined ? null : deps; 4159 var prevState = hook.memoizedState; 4160 if (prevState !== null) { 4161 // Assume these are defined. If they're not, areHookInputsEqual will warn. 4162 if (nextDeps !== null) { 4163 var prevDeps = prevState[1]; 4164 if (areHookInputsEqual(nextDeps, prevDeps)) { 4165 return prevState[0]; 4166 } 4167 } 4168 } 4169 var nextValue = nextCreate(); 4170 hook.memoizedState = [nextValue, nextDeps]; 4171 return nextValue; 4172 } 4173 4174 function dispatchAction(fiber, queue, action) { 4175 !(numberOfReRenders < RE_RENDER_LIMIT) ? reactProdInvariant('301') : void 0; 4176 4177 var alternate = fiber.alternate; 4178 if (fiber === currentlyRenderingFiber$1 || alternate !== null && alternate === currentlyRenderingFiber$1) { 4179 // This is a render phase update. Stash it in a lazily-created map of 4180 // queue -> linked list of updates. After this render pass, we'll restart 4181 // and apply the stashed updates on top of the work-in-progress hook. 4182 didScheduleRenderPhaseUpdate = true; 4183 var update = { 4184 expirationTime: renderExpirationTime, 4185 action: action, 4186 eagerReducer: null, 4187 eagerState: null, 4188 next: null 4189 }; 4190 if (renderPhaseUpdates === null) { 4191 renderPhaseUpdates = new Map(); 4192 } 4193 var firstRenderPhaseUpdate = renderPhaseUpdates.get(queue); 4194 if (firstRenderPhaseUpdate === undefined) { 4195 renderPhaseUpdates.set(queue, update); 4196 } else { 4197 // Append the update to the end of the list. 4198 var lastRenderPhaseUpdate = firstRenderPhaseUpdate; 4199 while (lastRenderPhaseUpdate.next !== null) { 4200 lastRenderPhaseUpdate = lastRenderPhaseUpdate.next; 4201 } 4202 lastRenderPhaseUpdate.next = update; 4203 } 4204 } else { 4205 flushPassiveEffects$1(); 4206 4207 var currentTime = requestCurrentTime(); 4208 var _expirationTime = computeExpirationForFiber(currentTime, fiber); 4209 4210 var _update2 = { 4211 expirationTime: _expirationTime, 4212 action: action, 4213 eagerReducer: null, 4214 eagerState: null, 4215 next: null 4216 }; 4217 4218 // Append the update to the end of the list. 4219 var _last = queue.last; 4220 if (_last === null) { 4221 // This is the first update. Create a circular list. 4222 _update2.next = _update2; 4223 } else { 4224 var first = _last.next; 4225 if (first !== null) { 4226 // Still circular. 4227 _update2.next = first; 4228 } 4229 _last.next = _update2; 4230 } 4231 queue.last = _update2; 4232 4233 if (fiber.expirationTime === NoWork && (alternate === null || alternate.expirationTime === NoWork)) { 4234 // The queue is currently empty, which means we can eagerly compute the 4235 // next state before entering the render phase. If the new state is the 4236 // same as the current state, we may be able to bail out entirely. 4237 var _lastRenderedReducer = queue.lastRenderedReducer; 4238 if (_lastRenderedReducer !== null) { 4239 try { 4240 var currentState = queue.lastRenderedState; 4241 var _eagerState = _lastRenderedReducer(currentState, action); 4242 // Stash the eagerly computed state, and the reducer used to compute 4243 // it, on the update object. If the reducer hasn't changed by the 4244 // time we enter the render phase, then the eager state can be used 4245 // without calling the reducer again. 4246 _update2.eagerReducer = _lastRenderedReducer; 4247 _update2.eagerState = _eagerState; 4248 if (is(_eagerState, currentState)) { 4249 // Fast path. We can bail out without scheduling React to re-render. 4250 // It's still possible that we'll need to rebase this update later, 4251 // if the component re-renders for a different reason and by that 4252 // time the reducer has changed. 4253 return; 4254 } 4255 } catch (error) { 4256 // Suppress the error. It will throw again in the render phase. 4257 } finally { 4258 4259 } 4260 } 4261 } 4262 scheduleWork(fiber, _expirationTime); 4263 } 4264 } 4265 4266 var ContextOnlyDispatcher = { 4267 readContext: readContext, 4268 4269 useCallback: throwInvalidHookError, 4270 useContext: throwInvalidHookError, 4271 useEffect: throwInvalidHookError, 4272 useImperativeHandle: throwInvalidHookError, 4273 useLayoutEffect: throwInvalidHookError, 4274 useMemo: throwInvalidHookError, 4275 useReducer: throwInvalidHookError, 4276 useRef: throwInvalidHookError, 4277 useState: throwInvalidHookError, 4278 useDebugValue: throwInvalidHookError 4279 }; 4280 4281 var HooksDispatcherOnMount = { 4282 readContext: readContext, 4283 4284 useCallback: mountCallback, 4285 useContext: readContext, 4286 useEffect: mountEffect, 4287 useImperativeHandle: mountImperativeHandle, 4288 useLayoutEffect: mountLayoutEffect, 4289 useMemo: mountMemo, 4290 useReducer: mountReducer, 4291 useRef: mountRef, 4292 useState: mountState, 4293 useDebugValue: mountDebugValue 4294 }; 4295 4296 var HooksDispatcherOnUpdate = { 4297 readContext: readContext, 4298 4299 useCallback: updateCallback, 4300 useContext: readContext, 4301 useEffect: updateEffect, 4302 useImperativeHandle: updateImperativeHandle, 4303 useLayoutEffect: updateLayoutEffect, 4304 useMemo: updateMemo, 4305 useReducer: updateReducer, 4306 useRef: updateRef, 4307 useState: updateState, 4308 useDebugValue: updateDebugValue 4309 }; 4310 4311 var commitTime = 0; 4312 var profilerStartTime = -1; 4313 4314 function getCommitTime() { 4315 return commitTime; 4316 } 4317 4318 function recordCommitTime() { 4319 if (!enableProfilerTimer) { 4320 return; 4321 } 4322 commitTime = now(); 4323 } 4324 4325 function startProfilerTimer(fiber) { 4326 if (!enableProfilerTimer) { 4327 return; 4328 } 4329 4330 profilerStartTime = now(); 4331 4332 if (fiber.actualStartTime < 0) { 4333 fiber.actualStartTime = now(); 4334 } 4335 } 4336 4337 function stopProfilerTimerIfRunning(fiber) { 4338 if (!enableProfilerTimer) { 4339 return; 4340 } 4341 profilerStartTime = -1; 4342 } 4343 4344 function stopProfilerTimerIfRunningAndRecordDelta(fiber, overrideBaseTime) { 4345 if (!enableProfilerTimer) { 4346 return; 4347 } 4348 4349 if (profilerStartTime >= 0) { 4350 var elapsedTime = now() - profilerStartTime; 4351 fiber.actualDuration += elapsedTime; 4352 if (overrideBaseTime) { 4353 fiber.selfBaseDuration = elapsedTime; 4354 } 4355 profilerStartTime = -1; 4356 } 4357 } 4358 4359 // The deepest Fiber on the stack involved in a hydration context. 4360 // This may have been an insertion or a hydration. 4361 var hydrationParentFiber = null; 4362 var nextHydratableInstance = null; 4363 var isHydrating = false; 4364 4365 function enterHydrationState(fiber) { 4366 if (!supportsHydration) { 4367 return false; 4368 } 4369 4370 var parentInstance = fiber.stateNode.containerInfo; 4371 nextHydratableInstance = getFirstHydratableChild(parentInstance); 4372 hydrationParentFiber = fiber; 4373 isHydrating = true; 4374 return true; 4375 } 4376 4377 function reenterHydrationStateFromDehydratedSuspenseInstance(fiber) { 4378 if (!supportsHydration) { 4379 return false; 4380 } 4381 4382 var suspenseInstance = fiber.stateNode; 4383 nextHydratableInstance = getNextHydratableSibling(suspenseInstance); 4384 popToNextHostParent(fiber); 4385 isHydrating = true; 4386 return true; 4387 } 4388 4389 function deleteHydratableInstance(returnFiber, instance) { 4390 var childToDelete = createFiberFromHostInstanceForDeletion(); 4391 childToDelete.stateNode = instance; 4392 childToDelete.return = returnFiber; 4393 childToDelete.effectTag = Deletion; 4394 4395 // This might seem like it belongs on progressedFirstDeletion. However, 4396 // these children are not part of the reconciliation list of children. 4397 // Even if we abort and rereconcile the children, that will try to hydrate 4398 // again and the nodes are still in the host tree so these will be 4399 // recreated. 4400 if (returnFiber.lastEffect !== null) { 4401 returnFiber.lastEffect.nextEffect = childToDelete; 4402 returnFiber.lastEffect = childToDelete; 4403 } else { 4404 returnFiber.firstEffect = returnFiber.lastEffect = childToDelete; 4405 } 4406 } 4407 4408 function insertNonHydratedInstance(returnFiber, fiber) { 4409 fiber.effectTag |= Placement; 4410 4411 } 4412 4413 function tryHydrate(fiber, nextInstance) { 4414 switch (fiber.tag) { 4415 case HostComponent: 4416 { 4417 var type = fiber.type; 4418 var props = fiber.pendingProps; 4419 var instance = canHydrateInstance(nextInstance, type, props); 4420 if (instance !== null) { 4421 fiber.stateNode = instance; 4422 return true; 4423 } 4424 return false; 4425 } 4426 case HostText: 4427 { 4428 var text = fiber.pendingProps; 4429 var textInstance = canHydrateTextInstance(nextInstance, text); 4430 if (textInstance !== null) { 4431 fiber.stateNode = textInstance; 4432 return true; 4433 } 4434 return false; 4435 } 4436 case SuspenseComponent: 4437 { 4438 if (enableSuspenseServerRenderer) { 4439 var suspenseInstance = canHydrateSuspenseInstance(nextInstance); 4440 if (suspenseInstance !== null) { 4441 // Downgrade the tag to a dehydrated component until we've hydrated it. 4442 fiber.tag = DehydratedSuspenseComponent; 4443 fiber.stateNode = suspenseInstance; 4444 return true; 4445 } 4446 } 4447 return false; 4448 } 4449 default: 4450 return false; 4451 } 4452 } 4453 4454 function tryToClaimNextHydratableInstance(fiber) { 4455 if (!isHydrating) { 4456 return; 4457 } 4458 var nextInstance = nextHydratableInstance; 4459 if (!nextInstance) { 4460 // Nothing to hydrate. Make it an insertion. 4461 insertNonHydratedInstance(hydrationParentFiber, fiber); 4462 isHydrating = false; 4463 hydrationParentFiber = fiber; 4464 return; 4465 } 4466 var firstAttemptedInstance = nextInstance; 4467 if (!tryHydrate(fiber, nextInstance)) { 4468 // If we can't hydrate this instance let's try the next one. 4469 // We use this as a heuristic. It's based on intuition and not data so it 4470 // might be flawed or unnecessary. 4471 nextInstance = getNextHydratableSibling(firstAttemptedInstance); 4472 if (!nextInstance || !tryHydrate(fiber, nextInstance)) { 4473 // Nothing to hydrate. Make it an insertion. 4474 insertNonHydratedInstance(hydrationParentFiber, fiber); 4475 isHydrating = false; 4476 hydrationParentFiber = fiber; 4477 return; 4478 } 4479 // We matched the next one, we'll now assume that the first one was 4480 // superfluous and we'll delete it. Since we can't eagerly delete it 4481 // we'll have to schedule a deletion. To do that, this node needs a dummy 4482 // fiber associated with it. 4483 deleteHydratableInstance(hydrationParentFiber, firstAttemptedInstance); 4484 } 4485 hydrationParentFiber = fiber; 4486 nextHydratableInstance = getFirstHydratableChild(nextInstance); 4487 } 4488 4489 function prepareToHydrateHostInstance(fiber, rootContainerInstance, hostContext) { 4490 if (!supportsHydration) { 4491 reactProdInvariant('175'); 4492 } 4493 4494 var instance = fiber.stateNode; 4495 var updatePayload = hydrateInstance(instance, fiber.type, fiber.memoizedProps, rootContainerInstance, hostContext, fiber); 4496 // TODO: Type this specific to this type of component. 4497 fiber.updateQueue = updatePayload; 4498 // If the update payload indicates that there is a change or if there 4499 // is a new ref we mark this as an update. 4500 if (updatePayload !== null) { 4501 return true; 4502 } 4503 return false; 4504 } 4505 4506 function prepareToHydrateHostTextInstance(fiber) { 4507 if (!supportsHydration) { 4508 reactProdInvariant('176'); 4509 } 4510 4511 var textInstance = fiber.stateNode; 4512 var textContent = fiber.memoizedProps; 4513 var shouldUpdate = hydrateTextInstance(textInstance, textContent, fiber); 4514 return shouldUpdate; 4515 } 4516 4517 function skipPastDehydratedSuspenseInstance(fiber) { 4518 if (!supportsHydration) { 4519 reactProdInvariant('316'); 4520 } 4521 var suspenseInstance = fiber.stateNode; 4522 !suspenseInstance ? reactProdInvariant('317') : void 0; 4523 nextHydratableInstance = getNextHydratableInstanceAfterSuspenseInstance(suspenseInstance); 4524 } 4525 4526 function popToNextHostParent(fiber) { 4527 var parent = fiber.return; 4528 while (parent !== null && parent.tag !== HostComponent && parent.tag !== HostRoot && parent.tag !== DehydratedSuspenseComponent) { 4529 parent = parent.return; 4530 } 4531 hydrationParentFiber = parent; 4532 } 4533 4534 function popHydrationState(fiber) { 4535 if (!supportsHydration) { 4536 return false; 4537 } 4538 if (fiber !== hydrationParentFiber) { 4539 // We're deeper than the current hydration context, inside an inserted 4540 // tree. 4541 return false; 4542 } 4543 if (!isHydrating) { 4544 // If we're not currently hydrating but we're in a hydration context, then 4545 // we were an insertion and now need to pop up reenter hydration of our 4546 // siblings. 4547 popToNextHostParent(fiber); 4548 isHydrating = true; 4549 return false; 4550 } 4551 4552 var type = fiber.type; 4553 4554 // If we have any remaining hydratable nodes, we need to delete them now. 4555 // We only do this deeper than head and body since they tend to have random 4556 // other nodes in them. We also ignore components with pure text content in 4557 // side of them. 4558 // TODO: Better heuristic. 4559 if (fiber.tag !== HostComponent || type !== 'head' && type !== 'body' && !shouldSetTextContent(type, fiber.memoizedProps)) { 4560 var nextInstance = nextHydratableInstance; 4561 while (nextInstance) { 4562 deleteHydratableInstance(fiber, nextInstance); 4563 nextInstance = getNextHydratableSibling(nextInstance); 4564 } 4565 } 4566 4567 popToNextHostParent(fiber); 4568 nextHydratableInstance = hydrationParentFiber ? getNextHydratableSibling(fiber.stateNode) : null; 4569 return true; 4570 } 4571 4572 function resetHydrationState() { 4573 if (!supportsHydration) { 4574 return; 4575 } 4576 4577 hydrationParentFiber = null; 4578 nextHydratableInstance = null; 4579 isHydrating = false; 4580 } 4581 4582 var ReactCurrentOwner$2 = ReactSharedInternals.ReactCurrentOwner; 4583 4584 var didReceiveUpdate = false; 4585 4586 4587 4588 function reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime) { 4589 if (current$$1 === null) { 4590 // If this is a fresh new component that hasn't been rendered yet, we 4591 // won't update its child set by applying minimal side-effects. Instead, 4592 // we will add them all to the child before it gets rendered. That means 4593 // we can optimize this reconciliation pass by not tracking side-effects. 4594 workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 4595 } else { 4596 // If the current child is the same as the work in progress, it means that 4597 // we haven't yet started any work on these children. Therefore, we use 4598 // the clone algorithm to create a copy of all the current children. 4599 4600 // If we had any progressed work already, that is invalid at this point so 4601 // let's throw it out. 4602 workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, nextChildren, renderExpirationTime); 4603 } 4604 } 4605 4606 function forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime) { 4607 // This function is fork of reconcileChildren. It's used in cases where we 4608 // want to reconcile without matching against the existing set. This has the 4609 // effect of all current children being unmounted; even if the type and key 4610 // are the same, the old child is unmounted and a new child is created. 4611 // 4612 // To do this, we're going to go through the reconcile algorithm twice. In 4613 // the first pass, we schedule a deletion for all the current children by 4614 // passing null. 4615 workInProgress.child = reconcileChildFibers(workInProgress, current$$1.child, null, renderExpirationTime); 4616 // In the second pass, we mount the new children. The trick here is that we 4617 // pass null in place of where we usually pass the current child set. This has 4618 // the effect of remounting all children regardless of whether their their 4619 // identity matches. 4620 workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 4621 } 4622 4623 function updateForwardRef(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { 4624 // TODO: current can be non-null here even if the component 4625 // hasn't yet mounted. This happens after the first render suspends. 4626 // We'll need to figure out if this is fine or can cause issues. 4627 4628 var render = Component.render; 4629 var ref = workInProgress.ref; 4630 4631 // The rest is a fork of updateFunctionComponent 4632 var nextChildren = void 0; 4633 prepareToReadContext(workInProgress, renderExpirationTime); 4634 { 4635 nextChildren = renderWithHooks(current$$1, workInProgress, render, nextProps, ref, renderExpirationTime); 4636 } 4637 4638 if (current$$1 !== null && !didReceiveUpdate) { 4639 bailoutHooks(current$$1, workInProgress, renderExpirationTime); 4640 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 4641 } 4642 4643 // React DevTools reads this flag. 4644 workInProgress.effectTag |= PerformedWork; 4645 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4646 return workInProgress.child; 4647 } 4648 4649 function updateMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { 4650 if (current$$1 === null) { 4651 var type = Component.type; 4652 if (isSimpleFunctionComponent(type) && Component.compare === null && 4653 // SimpleMemoComponent codepath doesn't resolve outer props either. 4654 Component.defaultProps === undefined) { 4655 // If this is a plain function component without default props, 4656 // and with only the default shallow comparison, we upgrade it 4657 // to a SimpleMemoComponent to allow fast path updates. 4658 workInProgress.tag = SimpleMemoComponent; 4659 workInProgress.type = type; 4660 return updateSimpleMemoComponent(current$$1, workInProgress, type, nextProps, updateExpirationTime, renderExpirationTime); 4661 } 4662 var child = createFiberFromTypeAndProps(Component.type, null, nextProps, null, workInProgress.mode, renderExpirationTime); 4663 child.ref = workInProgress.ref; 4664 child.return = workInProgress; 4665 workInProgress.child = child; 4666 return child; 4667 } 4668 var currentChild = current$$1.child; // This is always exactly one child 4669 if (updateExpirationTime < renderExpirationTime) { 4670 // This will be the props with resolved defaultProps, 4671 // unlike current.memoizedProps which will be the unresolved ones. 4672 var prevProps = currentChild.memoizedProps; 4673 // Default to shallow comparison 4674 var compare = Component.compare; 4675 compare = compare !== null ? compare : shallowEqual; 4676 if (compare(prevProps, nextProps) && current$$1.ref === workInProgress.ref) { 4677 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 4678 } 4679 } 4680 // React DevTools reads this flag. 4681 workInProgress.effectTag |= PerformedWork; 4682 var newChild = createWorkInProgress(currentChild, nextProps, renderExpirationTime); 4683 newChild.ref = workInProgress.ref; 4684 newChild.return = workInProgress; 4685 workInProgress.child = newChild; 4686 return newChild; 4687 } 4688 4689 function updateSimpleMemoComponent(current$$1, workInProgress, Component, nextProps, updateExpirationTime, renderExpirationTime) { 4690 // TODO: current can be non-null here even if the component 4691 // hasn't yet mounted. This happens when the inner render suspends. 4692 // We'll need to figure out if this is fine or can cause issues. 4693 4694 if (current$$1 !== null) { 4695 var prevProps = current$$1.memoizedProps; 4696 if (shallowEqual(prevProps, nextProps) && current$$1.ref === workInProgress.ref) { 4697 didReceiveUpdate = false; 4698 if (updateExpirationTime < renderExpirationTime) { 4699 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 4700 } 4701 } 4702 } 4703 return updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime); 4704 } 4705 4706 function updateFragment(current$$1, workInProgress, renderExpirationTime) { 4707 var nextChildren = workInProgress.pendingProps; 4708 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4709 return workInProgress.child; 4710 } 4711 4712 function updateMode(current$$1, workInProgress, renderExpirationTime) { 4713 var nextChildren = workInProgress.pendingProps.children; 4714 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4715 return workInProgress.child; 4716 } 4717 4718 function updateProfiler(current$$1, workInProgress, renderExpirationTime) { 4719 if (enableProfilerTimer) { 4720 workInProgress.effectTag |= Update; 4721 } 4722 var nextProps = workInProgress.pendingProps; 4723 var nextChildren = nextProps.children; 4724 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4725 return workInProgress.child; 4726 } 4727 4728 function markRef(current$$1, workInProgress) { 4729 var ref = workInProgress.ref; 4730 if (current$$1 === null && ref !== null || current$$1 !== null && current$$1.ref !== ref) { 4731 // Schedule a Ref effect 4732 workInProgress.effectTag |= Ref; 4733 } 4734 } 4735 4736 function updateFunctionComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { 4737 var unmaskedContext = getUnmaskedContext(workInProgress, Component, true); 4738 var context = getMaskedContext(workInProgress, unmaskedContext); 4739 4740 var nextChildren = void 0; 4741 prepareToReadContext(workInProgress, renderExpirationTime); 4742 { 4743 nextChildren = renderWithHooks(current$$1, workInProgress, Component, nextProps, context, renderExpirationTime); 4744 } 4745 4746 if (current$$1 !== null && !didReceiveUpdate) { 4747 bailoutHooks(current$$1, workInProgress, renderExpirationTime); 4748 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 4749 } 4750 4751 // React DevTools reads this flag. 4752 workInProgress.effectTag |= PerformedWork; 4753 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4754 return workInProgress.child; 4755 } 4756 4757 function updateClassComponent(current$$1, workInProgress, Component, nextProps, renderExpirationTime) { 4758 var hasContext = void 0; 4759 if (isContextProvider(Component)) { 4760 hasContext = true; 4761 pushContextProvider(workInProgress); 4762 } else { 4763 hasContext = false; 4764 } 4765 prepareToReadContext(workInProgress, renderExpirationTime); 4766 4767 var instance = workInProgress.stateNode; 4768 var shouldUpdate = void 0; 4769 if (instance === null) { 4770 if (current$$1 !== null) { 4771 // An class component without an instance only mounts if it suspended 4772 // inside a non- concurrent tree, in an inconsistent state. We want to 4773 // tree it like a new mount, even though an empty version of it already 4774 // committed. Disconnect the alternate pointers. 4775 current$$1.alternate = null; 4776 workInProgress.alternate = null; 4777 // Since this is conceptually a new fiber, schedule a Placement effect 4778 workInProgress.effectTag |= Placement; 4779 } 4780 // In the initial pass we might need to construct the instance. 4781 constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 4782 mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 4783 shouldUpdate = true; 4784 } else if (current$$1 === null) { 4785 // In a resume, we'll already have an instance we can reuse. 4786 shouldUpdate = resumeMountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 4787 } else { 4788 shouldUpdate = updateClassInstance(current$$1, workInProgress, Component, nextProps, renderExpirationTime); 4789 } 4790 var nextUnitOfWork = finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime); 4791 return nextUnitOfWork; 4792 } 4793 4794 function finishClassComponent(current$$1, workInProgress, Component, shouldUpdate, hasContext, renderExpirationTime) { 4795 // Refs should update even if shouldComponentUpdate returns false 4796 markRef(current$$1, workInProgress); 4797 4798 var didCaptureError = (workInProgress.effectTag & DidCapture) !== NoEffect; 4799 4800 if (!shouldUpdate && !didCaptureError) { 4801 // Context providers should defer to sCU for rendering 4802 if (hasContext) { 4803 invalidateContextProvider(workInProgress, Component, false); 4804 } 4805 4806 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 4807 } 4808 4809 var instance = workInProgress.stateNode; 4810 4811 // Rerender 4812 ReactCurrentOwner$2.current = workInProgress; 4813 var nextChildren = void 0; 4814 if (didCaptureError && typeof Component.getDerivedStateFromError !== 'function') { 4815 // If we captured an error, but getDerivedStateFrom catch is not defined, 4816 // unmount all the children. componentDidCatch will schedule an update to 4817 // re-render a fallback. This is temporary until we migrate everyone to 4818 // the new API. 4819 // TODO: Warn in a future release. 4820 nextChildren = null; 4821 4822 if (enableProfilerTimer) { 4823 stopProfilerTimerIfRunning(workInProgress); 4824 } 4825 } else { 4826 { 4827 nextChildren = instance.render(); 4828 } 4829 } 4830 4831 // React DevTools reads this flag. 4832 workInProgress.effectTag |= PerformedWork; 4833 if (current$$1 !== null && didCaptureError) { 4834 // If we're recovering from an error, reconcile without reusing any of 4835 // the existing children. Conceptually, the normal children and the children 4836 // that are shown on error are two different sets, so we shouldn't reuse 4837 // normal children even if their identities match. 4838 forceUnmountCurrentAndReconcile(current$$1, workInProgress, nextChildren, renderExpirationTime); 4839 } else { 4840 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4841 } 4842 4843 // Memoize state using the values we just used to render. 4844 // TODO: Restructure so we never read values from the instance. 4845 workInProgress.memoizedState = instance.state; 4846 4847 // The context might have changed so we need to recalculate it. 4848 if (hasContext) { 4849 invalidateContextProvider(workInProgress, Component, true); 4850 } 4851 4852 return workInProgress.child; 4853 } 4854 4855 function pushHostRootContext(workInProgress) { 4856 var root = workInProgress.stateNode; 4857 if (root.pendingContext) { 4858 pushTopLevelContextObject(workInProgress, root.pendingContext, root.pendingContext !== root.context); 4859 } else if (root.context) { 4860 // Should always be set 4861 pushTopLevelContextObject(workInProgress, root.context, false); 4862 } 4863 pushHostContainer(workInProgress, root.containerInfo); 4864 } 4865 4866 function updateHostRoot(current$$1, workInProgress, renderExpirationTime) { 4867 pushHostRootContext(workInProgress); 4868 var updateQueue = workInProgress.updateQueue; 4869 !(updateQueue !== null) ? reactProdInvariant('282') : void 0; 4870 var nextProps = workInProgress.pendingProps; 4871 var prevState = workInProgress.memoizedState; 4872 var prevChildren = prevState !== null ? prevState.element : null; 4873 processUpdateQueue(workInProgress, updateQueue, nextProps, null, renderExpirationTime); 4874 var nextState = workInProgress.memoizedState; 4875 // Caution: React DevTools currently depends on this property 4876 // being called "element". 4877 var nextChildren = nextState.element; 4878 if (nextChildren === prevChildren) { 4879 // If the state is the same as before, that's a bailout because we had 4880 // no work that expires at this time. 4881 resetHydrationState(); 4882 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 4883 } 4884 var root = workInProgress.stateNode; 4885 if ((current$$1 === null || current$$1.child === null) && root.hydrate && enterHydrationState(workInProgress)) { 4886 // If we don't have any current children this might be the first pass. 4887 // We always try to hydrate. If this isn't a hydration pass there won't 4888 // be any children to hydrate which is effectively the same thing as 4889 // not hydrating. 4890 4891 // This is a bit of a hack. We track the host root as a placement to 4892 // know that we're currently in a mounting state. That way isMounted 4893 // works as expected. We must reset this before committing. 4894 // TODO: Delete this when we delete isMounted and findDOMNode. 4895 workInProgress.effectTag |= Placement; 4896 4897 // Ensure that children mount into this root without tracking 4898 // side-effects. This ensures that we don't store Placement effects on 4899 // nodes that will be hydrated. 4900 workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 4901 } else { 4902 // Otherwise reset hydration state in case we aborted and resumed another 4903 // root. 4904 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4905 resetHydrationState(); 4906 } 4907 return workInProgress.child; 4908 } 4909 4910 function updateHostComponent(current$$1, workInProgress, renderExpirationTime) { 4911 pushHostContext(workInProgress); 4912 4913 if (current$$1 === null) { 4914 tryToClaimNextHydratableInstance(workInProgress); 4915 } 4916 4917 var type = workInProgress.type; 4918 var nextProps = workInProgress.pendingProps; 4919 var prevProps = current$$1 !== null ? current$$1.memoizedProps : null; 4920 4921 var nextChildren = nextProps.children; 4922 var isDirectTextChild = shouldSetTextContent(type, nextProps); 4923 4924 if (isDirectTextChild) { 4925 // We special case a direct text child of a host node. This is a common 4926 // case. We won't handle it as a reified child. We will instead handle 4927 // this in the host environment that also have access to this prop. That 4928 // avoids allocating another HostText fiber and traversing it. 4929 nextChildren = null; 4930 } else if (prevProps !== null && shouldSetTextContent(type, prevProps)) { 4931 // If we're switching from a direct text child to a normal child, or to 4932 // empty, we need to schedule the text content to be reset. 4933 workInProgress.effectTag |= ContentReset; 4934 } 4935 4936 markRef(current$$1, workInProgress); 4937 4938 // Check the host config to see if the children are offscreen/hidden. 4939 if (renderExpirationTime !== Never && workInProgress.mode & ConcurrentMode && shouldDeprioritizeSubtree(type, nextProps)) { 4940 // Schedule this fiber to re-render at offscreen priority. Then bailout. 4941 workInProgress.expirationTime = workInProgress.childExpirationTime = Never; 4942 return null; 4943 } 4944 4945 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 4946 return workInProgress.child; 4947 } 4948 4949 function updateHostText(current$$1, workInProgress) { 4950 if (current$$1 === null) { 4951 tryToClaimNextHydratableInstance(workInProgress); 4952 } 4953 // Nothing to do here. This is terminal. We'll do the completion step 4954 // immediately after. 4955 return null; 4956 } 4957 4958 function mountLazyComponent(_current, workInProgress, elementType, updateExpirationTime, renderExpirationTime) { 4959 if (_current !== null) { 4960 // An lazy component only mounts if it suspended inside a non- 4961 // concurrent tree, in an inconsistent state. We want to treat it like 4962 // a new mount, even though an empty version of it already committed. 4963 // Disconnect the alternate pointers. 4964 _current.alternate = null; 4965 workInProgress.alternate = null; 4966 // Since this is conceptually a new fiber, schedule a Placement effect 4967 workInProgress.effectTag |= Placement; 4968 } 4969 4970 var props = workInProgress.pendingProps; 4971 // We can't start a User Timing measurement with correct label yet. 4972 // Cancel and resume right after we know the tag. 4973 cancelWorkTimer(workInProgress); 4974 var Component = readLazyComponentType(elementType); 4975 // Store the unwrapped component in the type. 4976 workInProgress.type = Component; 4977 var resolvedTag = workInProgress.tag = resolveLazyComponentTag(Component); 4978 startWorkTimer(workInProgress); 4979 var resolvedProps = resolveDefaultProps(Component, props); 4980 var child = void 0; 4981 switch (resolvedTag) { 4982 case FunctionComponent: 4983 { 4984 child = updateFunctionComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); 4985 break; 4986 } 4987 case ClassComponent: 4988 { 4989 child = updateClassComponent(null, workInProgress, Component, resolvedProps, renderExpirationTime); 4990 break; 4991 } 4992 case ForwardRef: 4993 { 4994 child = updateForwardRef(null, workInProgress, Component, resolvedProps, renderExpirationTime); 4995 break; 4996 } 4997 case MemoComponent: 4998 { 4999 child = updateMemoComponent(null, workInProgress, Component, resolveDefaultProps(Component.type, resolvedProps), // The inner type can have defaults too 5000 updateExpirationTime, renderExpirationTime); 5001 break; 5002 } 5003 default: 5004 { 5005 var hint = ''; 5006 reactProdInvariant('306', Component, hint); 5007 } 5008 } 5009 return child; 5010 } 5011 5012 function mountIncompleteClassComponent(_current, workInProgress, Component, nextProps, renderExpirationTime) { 5013 if (_current !== null) { 5014 // An incomplete component only mounts if it suspended inside a non- 5015 // concurrent tree, in an inconsistent state. We want to treat it like 5016 // a new mount, even though an empty version of it already committed. 5017 // Disconnect the alternate pointers. 5018 _current.alternate = null; 5019 workInProgress.alternate = null; 5020 // Since this is conceptually a new fiber, schedule a Placement effect 5021 workInProgress.effectTag |= Placement; 5022 } 5023 5024 // Promote the fiber to a class and try rendering again. 5025 workInProgress.tag = ClassComponent; 5026 5027 // The rest of this function is a fork of `updateClassComponent` 5028 5029 // Push context providers early to prevent context stack mismatches. 5030 // During mounting we don't know the child context yet as the instance doesn't exist. 5031 // We will invalidate the child context in finishClassComponent() right after rendering. 5032 var hasContext = void 0; 5033 if (isContextProvider(Component)) { 5034 hasContext = true; 5035 pushContextProvider(workInProgress); 5036 } else { 5037 hasContext = false; 5038 } 5039 prepareToReadContext(workInProgress, renderExpirationTime); 5040 5041 constructClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 5042 mountClassInstance(workInProgress, Component, nextProps, renderExpirationTime); 5043 5044 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); 5045 } 5046 5047 function mountIndeterminateComponent(_current, workInProgress, Component, renderExpirationTime) { 5048 if (_current !== null) { 5049 // An indeterminate component only mounts if it suspended inside a non- 5050 // concurrent tree, in an inconsistent state. We want to treat it like 5051 // a new mount, even though an empty version of it already committed. 5052 // Disconnect the alternate pointers. 5053 _current.alternate = null; 5054 workInProgress.alternate = null; 5055 // Since this is conceptually a new fiber, schedule a Placement effect 5056 workInProgress.effectTag |= Placement; 5057 } 5058 5059 var props = workInProgress.pendingProps; 5060 var unmaskedContext = getUnmaskedContext(workInProgress, Component, false); 5061 var context = getMaskedContext(workInProgress, unmaskedContext); 5062 5063 prepareToReadContext(workInProgress, renderExpirationTime); 5064 5065 var value = void 0; 5066 5067 { 5068 value = renderWithHooks(null, workInProgress, Component, props, context, renderExpirationTime); 5069 } 5070 // React DevTools reads this flag. 5071 workInProgress.effectTag |= PerformedWork; 5072 5073 if (typeof value === 'object' && value !== null && typeof value.render === 'function' && value.$$typeof === undefined) { 5074 // Proceed under the assumption that this is a class instance 5075 workInProgress.tag = ClassComponent; 5076 5077 // Throw out any hooks that were used. 5078 resetHooks(); 5079 5080 // Push context providers early to prevent context stack mismatches. 5081 // During mounting we don't know the child context yet as the instance doesn't exist. 5082 // We will invalidate the child context in finishClassComponent() right after rendering. 5083 var hasContext = false; 5084 if (isContextProvider(Component)) { 5085 hasContext = true; 5086 pushContextProvider(workInProgress); 5087 } else { 5088 hasContext = false; 5089 } 5090 5091 workInProgress.memoizedState = value.state !== null && value.state !== undefined ? value.state : null; 5092 5093 var getDerivedStateFromProps = Component.getDerivedStateFromProps; 5094 if (typeof getDerivedStateFromProps === 'function') { 5095 applyDerivedStateFromProps(workInProgress, Component, getDerivedStateFromProps, props); 5096 } 5097 5098 adoptClassInstance(workInProgress, value); 5099 mountClassInstance(workInProgress, Component, props, renderExpirationTime); 5100 return finishClassComponent(null, workInProgress, Component, true, hasContext, renderExpirationTime); 5101 } else { 5102 // Proceed under the assumption that this is a function component 5103 workInProgress.tag = FunctionComponent; 5104 reconcileChildren(null, workInProgress, value, renderExpirationTime); 5105 return workInProgress.child; 5106 } 5107 } 5108 5109 function updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { 5110 var mode = workInProgress.mode; 5111 var nextProps = workInProgress.pendingProps; 5112 5113 // We should attempt to render the primary children unless this boundary 5114 // already suspended during this render (`alreadyCaptured` is true). 5115 var nextState = workInProgress.memoizedState; 5116 5117 var nextDidTimeout = void 0; 5118 if ((workInProgress.effectTag & DidCapture) === NoEffect) { 5119 // This is the first attempt. 5120 nextState = null; 5121 nextDidTimeout = false; 5122 } else { 5123 // Something in this boundary's subtree already suspended. Switch to 5124 // rendering the fallback children. 5125 nextState = { 5126 timedOutAt: nextState !== null ? nextState.timedOutAt : NoWork 5127 }; 5128 nextDidTimeout = true; 5129 workInProgress.effectTag &= ~DidCapture; 5130 } 5131 5132 // This next part is a bit confusing. If the children timeout, we switch to 5133 // showing the fallback children in place of the "primary" children. 5134 // However, we don't want to delete the primary children because then their 5135 // state will be lost (both the React state and the host state, e.g. 5136 // uncontrolled form inputs). Instead we keep them mounted and hide them. 5137 // Both the fallback children AND the primary children are rendered at the 5138 // same time. Once the primary children are un-suspended, we can delete 5139 // the fallback children — don't need to preserve their state. 5140 // 5141 // The two sets of children are siblings in the host environment, but 5142 // semantically, for purposes of reconciliation, they are two separate sets. 5143 // So we store them using two fragment fibers. 5144 // 5145 // However, we want to avoid allocating extra fibers for every placeholder. 5146 // They're only necessary when the children time out, because that's the 5147 // only time when both sets are mounted. 5148 // 5149 // So, the extra fragment fibers are only used if the children time out. 5150 // Otherwise, we render the primary children directly. This requires some 5151 // custom reconciliation logic to preserve the state of the primary 5152 // children. It's essentially a very basic form of re-parenting. 5153 5154 // `child` points to the child fiber. In the normal case, this is the first 5155 // fiber of the primary children set. In the timed-out case, it's a 5156 // a fragment fiber containing the primary children. 5157 var child = void 0; 5158 // `next` points to the next fiber React should render. In the normal case, 5159 // it's the same as `child`: the first fiber of the primary children set. 5160 // In the timed-out case, it's a fragment fiber containing the *fallback* 5161 // children -- we skip over the primary children entirely. 5162 var next = void 0; 5163 if (current$$1 === null) { 5164 if (enableSuspenseServerRenderer) { 5165 // If we're currently hydrating, try to hydrate this boundary. 5166 // But only if this has a fallback. 5167 if (nextProps.fallback !== undefined) { 5168 tryToClaimNextHydratableInstance(workInProgress); 5169 // This could've changed the tag if this was a dehydrated suspense component. 5170 if (workInProgress.tag === DehydratedSuspenseComponent) { 5171 return updateDehydratedSuspenseComponent(null, workInProgress, renderExpirationTime); 5172 } 5173 } 5174 } 5175 5176 // This is the initial mount. This branch is pretty simple because there's 5177 // no previous state that needs to be preserved. 5178 if (nextDidTimeout) { 5179 // Mount separate fragments for primary and fallback children. 5180 var nextFallbackChildren = nextProps.fallback; 5181 var primaryChildFragment = createFiberFromFragment(null, mode, NoWork, null); 5182 5183 if ((workInProgress.mode & ConcurrentMode) === NoContext) { 5184 // Outside of concurrent mode, we commit the effects from the 5185 var progressedState = workInProgress.memoizedState; 5186 var progressedPrimaryChild = progressedState !== null ? workInProgress.child.child : workInProgress.child; 5187 primaryChildFragment.child = progressedPrimaryChild; 5188 } 5189 5190 var fallbackChildFragment = createFiberFromFragment(nextFallbackChildren, mode, renderExpirationTime, null); 5191 primaryChildFragment.sibling = fallbackChildFragment; 5192 child = primaryChildFragment; 5193 // Skip the primary children, and continue working on the 5194 // fallback children. 5195 next = fallbackChildFragment; 5196 child.return = next.return = workInProgress; 5197 } else { 5198 // Mount the primary children without an intermediate fragment fiber. 5199 var nextPrimaryChildren = nextProps.children; 5200 child = next = mountChildFibers(workInProgress, null, nextPrimaryChildren, renderExpirationTime); 5201 } 5202 } else { 5203 // This is an update. This branch is more complicated because we need to 5204 // ensure the state of the primary children is preserved. 5205 var prevState = current$$1.memoizedState; 5206 var prevDidTimeout = prevState !== null; 5207 if (prevDidTimeout) { 5208 // The current tree already timed out. That means each child set is 5209 var currentPrimaryChildFragment = current$$1.child; 5210 var currentFallbackChildFragment = currentPrimaryChildFragment.sibling; 5211 if (nextDidTimeout) { 5212 // Still timed out. Reuse the current primary children by cloning 5213 // its fragment. We're going to skip over these entirely. 5214 var _nextFallbackChildren = nextProps.fallback; 5215 var _primaryChildFragment = createWorkInProgress(currentPrimaryChildFragment, currentPrimaryChildFragment.pendingProps, NoWork); 5216 5217 if ((workInProgress.mode & ConcurrentMode) === NoContext) { 5218 // Outside of concurrent mode, we commit the effects from the 5219 var _progressedState = workInProgress.memoizedState; 5220 var _progressedPrimaryChild = _progressedState !== null ? workInProgress.child.child : workInProgress.child; 5221 if (_progressedPrimaryChild !== currentPrimaryChildFragment.child) { 5222 _primaryChildFragment.child = _progressedPrimaryChild; 5223 } 5224 } 5225 5226 // Because primaryChildFragment is a new fiber that we're inserting as the 5227 // parent of a new tree, we need to set its treeBaseDuration. 5228 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 5229 // treeBaseDuration is the sum of all the child tree base durations. 5230 var treeBaseDuration = 0; 5231 var hiddenChild = _primaryChildFragment.child; 5232 while (hiddenChild !== null) { 5233 treeBaseDuration += hiddenChild.treeBaseDuration; 5234 hiddenChild = hiddenChild.sibling; 5235 } 5236 _primaryChildFragment.treeBaseDuration = treeBaseDuration; 5237 } 5238 5239 // Clone the fallback child fragment, too. These we'll continue 5240 // working on. 5241 var _fallbackChildFragment = _primaryChildFragment.sibling = createWorkInProgress(currentFallbackChildFragment, _nextFallbackChildren, currentFallbackChildFragment.expirationTime); 5242 child = _primaryChildFragment; 5243 _primaryChildFragment.childExpirationTime = NoWork; 5244 // Skip the primary children, and continue working on the 5245 // fallback children. 5246 next = _fallbackChildFragment; 5247 child.return = next.return = workInProgress; 5248 } else { 5249 // No longer suspended. Switch back to showing the primary children, 5250 // and remove the intermediate fragment fiber. 5251 var _nextPrimaryChildren = nextProps.children; 5252 var currentPrimaryChild = currentPrimaryChildFragment.child; 5253 var primaryChild = reconcileChildFibers(workInProgress, currentPrimaryChild, _nextPrimaryChildren, renderExpirationTime); 5254 5255 // If this render doesn't suspend, we need to delete the fallback 5256 // children. Wait until the complete phase, after we've confirmed the 5257 // fallback is no longer needed. 5258 // TODO: Would it be better to store the fallback fragment on 5259 // the stateNode? 5260 5261 // Continue rendering the children, like we normally do. 5262 child = next = primaryChild; 5263 } 5264 } else { 5265 // The current tree has not already timed out. That means the primary 5266 // children are not wrapped in a fragment fiber. 5267 var _currentPrimaryChild = current$$1.child; 5268 if (nextDidTimeout) { 5269 // Timed out. Wrap the children in a fragment fiber to keep them 5270 // separate from the fallback children. 5271 var _nextFallbackChildren2 = nextProps.fallback; 5272 var _primaryChildFragment2 = createFiberFromFragment( 5273 // It shouldn't matter what the pending props are because we aren't 5274 // going to render this fragment. 5275 null, mode, NoWork, null); 5276 _primaryChildFragment2.child = _currentPrimaryChild; 5277 5278 // Even though we're creating a new fiber, there are no new children, 5279 // because we're reusing an already mounted tree. So we don't need to 5280 // schedule a placement. 5281 // primaryChildFragment.effectTag |= Placement; 5282 5283 if ((workInProgress.mode & ConcurrentMode) === NoContext) { 5284 // Outside of concurrent mode, we commit the effects from the 5285 var _progressedState2 = workInProgress.memoizedState; 5286 var _progressedPrimaryChild2 = _progressedState2 !== null ? workInProgress.child.child : workInProgress.child; 5287 _primaryChildFragment2.child = _progressedPrimaryChild2; 5288 } 5289 5290 // Because primaryChildFragment is a new fiber that we're inserting as the 5291 // parent of a new tree, we need to set its treeBaseDuration. 5292 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 5293 // treeBaseDuration is the sum of all the child tree base durations. 5294 var _treeBaseDuration = 0; 5295 var _hiddenChild = _primaryChildFragment2.child; 5296 while (_hiddenChild !== null) { 5297 _treeBaseDuration += _hiddenChild.treeBaseDuration; 5298 _hiddenChild = _hiddenChild.sibling; 5299 } 5300 _primaryChildFragment2.treeBaseDuration = _treeBaseDuration; 5301 } 5302 5303 // Create a fragment from the fallback children, too. 5304 var _fallbackChildFragment2 = _primaryChildFragment2.sibling = createFiberFromFragment(_nextFallbackChildren2, mode, renderExpirationTime, null); 5305 _fallbackChildFragment2.effectTag |= Placement; 5306 child = _primaryChildFragment2; 5307 _primaryChildFragment2.childExpirationTime = NoWork; 5308 // Skip the primary children, and continue working on the 5309 // fallback children. 5310 next = _fallbackChildFragment2; 5311 child.return = next.return = workInProgress; 5312 } else { 5313 // Still haven't timed out. Continue rendering the children, like we 5314 // normally do. 5315 var _nextPrimaryChildren2 = nextProps.children; 5316 next = child = reconcileChildFibers(workInProgress, _currentPrimaryChild, _nextPrimaryChildren2, renderExpirationTime); 5317 } 5318 } 5319 workInProgress.stateNode = current$$1.stateNode; 5320 } 5321 5322 workInProgress.memoizedState = nextState; 5323 workInProgress.child = child; 5324 return next; 5325 } 5326 5327 function updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime) { 5328 if (current$$1 === null) { 5329 // During the first pass, we'll bail out and not drill into the children. 5330 // Instead, we'll leave the content in place and try to hydrate it later. 5331 workInProgress.expirationTime = Never; 5332 return null; 5333 } 5334 // We use childExpirationTime to indicate that a child might depend on context, so if 5335 // any context has changed, we need to treat is as if the input might have changed. 5336 var hasContextChanged$$1 = current$$1.childExpirationTime >= renderExpirationTime; 5337 if (didReceiveUpdate || hasContextChanged$$1) { 5338 // This boundary has changed since the first render. This means that we are now unable to 5339 // hydrate it. We might still be able to hydrate it using an earlier expiration time but 5340 // during this render we can't. Instead, we're going to delete the whole subtree and 5341 // instead inject a new real Suspense boundary to take its place, which may render content 5342 // or fallback. The real Suspense boundary will suspend for a while so we have some time 5343 // to ensure it can produce real content, but all state and pending events will be lost. 5344 5345 // Detach from the current dehydrated boundary. 5346 current$$1.alternate = null; 5347 workInProgress.alternate = null; 5348 5349 // Insert a deletion in the effect list. 5350 var returnFiber = workInProgress.return; 5351 !(returnFiber !== null) ? reactProdInvariant('315') : void 0; 5352 var last = returnFiber.lastEffect; 5353 if (last !== null) { 5354 last.nextEffect = current$$1; 5355 returnFiber.lastEffect = current$$1; 5356 } else { 5357 returnFiber.firstEffect = returnFiber.lastEffect = current$$1; 5358 } 5359 current$$1.nextEffect = null; 5360 current$$1.effectTag = Deletion; 5361 5362 // Upgrade this work in progress to a real Suspense component. 5363 workInProgress.tag = SuspenseComponent; 5364 workInProgress.stateNode = null; 5365 workInProgress.memoizedState = null; 5366 // This is now an insertion. 5367 workInProgress.effectTag |= Placement; 5368 // Retry as a real Suspense component. 5369 return updateSuspenseComponent(null, workInProgress, renderExpirationTime); 5370 } 5371 if ((workInProgress.effectTag & DidCapture) === NoEffect) { 5372 // This is the first attempt. 5373 reenterHydrationStateFromDehydratedSuspenseInstance(workInProgress); 5374 var nextProps = workInProgress.pendingProps; 5375 var nextChildren = nextProps.children; 5376 workInProgress.child = mountChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 5377 return workInProgress.child; 5378 } else { 5379 // Something suspended. Leave the existing children in place. 5380 // TODO: In non-concurrent mode, should we commit the nodes we have hydrated so far? 5381 workInProgress.child = null; 5382 return null; 5383 } 5384 } 5385 5386 function updatePortalComponent(current$$1, workInProgress, renderExpirationTime) { 5387 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); 5388 var nextChildren = workInProgress.pendingProps; 5389 if (current$$1 === null) { 5390 // Portals are special because we don't append the children during mount 5391 // but at commit. Therefore we need to track insertions which the normal 5392 // flow doesn't do during mount. This doesn't happen at the root because 5393 // the root always starts with a "current" with a null child. 5394 // TODO: Consider unifying this with how the root works. 5395 workInProgress.child = reconcileChildFibers(workInProgress, null, nextChildren, renderExpirationTime); 5396 } else { 5397 reconcileChildren(current$$1, workInProgress, nextChildren, renderExpirationTime); 5398 } 5399 return workInProgress.child; 5400 } 5401 5402 function updateContextProvider(current$$1, workInProgress, renderExpirationTime) { 5403 var providerType = workInProgress.type; 5404 var context = providerType._context; 5405 5406 var newProps = workInProgress.pendingProps; 5407 var oldProps = workInProgress.memoizedProps; 5408 5409 var newValue = newProps.value; 5410 5411 pushProvider(workInProgress, newValue); 5412 5413 if (oldProps !== null) { 5414 var oldValue = oldProps.value; 5415 var changedBits = calculateChangedBits(context, newValue, oldValue); 5416 if (changedBits === 0) { 5417 // No change. Bailout early if children are the same. 5418 if (oldProps.children === newProps.children && !hasContextChanged()) { 5419 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 5420 } 5421 } else { 5422 // The context value changed. Search for matching consumers and schedule 5423 // them to update. 5424 propagateContextChange(workInProgress, context, changedBits, renderExpirationTime); 5425 } 5426 } 5427 5428 var newChildren = newProps.children; 5429 reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); 5430 return workInProgress.child; 5431 } 5432 5433 function updateContextConsumer(current$$1, workInProgress, renderExpirationTime) { 5434 var context = workInProgress.type; 5435 // The logic below for Context differs depending on PROD or DEV mode. In 5436 // DEV mode, we create a separate object for Context.Consumer that acts 5437 // like a proxy to Context. This proxy object adds unnecessary code in PROD 5438 // so we use the old behaviour (Context.Consumer references Context) to 5439 // reduce size and overhead. The separate object references context via 5440 // a property called "_context", which also gives us the ability to check 5441 // in DEV mode if this property exists or not and warn if it does not. 5442 var newProps = workInProgress.pendingProps; 5443 var render = newProps.children; 5444 5445 prepareToReadContext(workInProgress, renderExpirationTime); 5446 var newValue = readContext(context, newProps.unstable_observedBits); 5447 var newChildren = void 0; 5448 { 5449 newChildren = render(newValue); 5450 } 5451 5452 // React DevTools reads this flag. 5453 workInProgress.effectTag |= PerformedWork; 5454 reconcileChildren(current$$1, workInProgress, newChildren, renderExpirationTime); 5455 return workInProgress.child; 5456 } 5457 5458 function markWorkInProgressReceivedUpdate() { 5459 didReceiveUpdate = true; 5460 } 5461 5462 function bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime) { 5463 cancelWorkTimer(workInProgress); 5464 5465 if (current$$1 !== null) { 5466 // Reuse previous context list 5467 workInProgress.contextDependencies = current$$1.contextDependencies; 5468 } 5469 5470 if (enableProfilerTimer) { 5471 // Don't update "base" render times for bailouts. 5472 stopProfilerTimerIfRunning(workInProgress); 5473 } 5474 5475 // Check if the children have any pending work. 5476 var childExpirationTime = workInProgress.childExpirationTime; 5477 if (childExpirationTime < renderExpirationTime) { 5478 // The children don't have any work either. We can skip them. 5479 // TODO: Once we add back resuming, we should check if the children are 5480 // a work-in-progress set. If so, we need to transfer their effects. 5481 return null; 5482 } else { 5483 // This fiber doesn't have work, but its subtree does. Clone the child 5484 // fibers and continue. 5485 cloneChildFibers(current$$1, workInProgress); 5486 return workInProgress.child; 5487 } 5488 } 5489 5490 function beginWork(current$$1, workInProgress, renderExpirationTime) { 5491 var updateExpirationTime = workInProgress.expirationTime; 5492 5493 if (current$$1 !== null) { 5494 var oldProps = current$$1.memoizedProps; 5495 var newProps = workInProgress.pendingProps; 5496 5497 if (oldProps !== newProps || hasContextChanged()) { 5498 // If props or context changed, mark the fiber as having performed work. 5499 // This may be unset if the props are determined to be equal later (memo). 5500 didReceiveUpdate = true; 5501 } else if (updateExpirationTime < renderExpirationTime) { 5502 didReceiveUpdate = false; 5503 // This fiber does not have any pending work. Bailout without entering 5504 // the begin phase. There's still some bookkeeping we that needs to be done 5505 // in this optimized path, mostly pushing stuff onto the stack. 5506 switch (workInProgress.tag) { 5507 case HostRoot: 5508 pushHostRootContext(workInProgress); 5509 resetHydrationState(); 5510 break; 5511 case HostComponent: 5512 pushHostContext(workInProgress); 5513 break; 5514 case ClassComponent: 5515 { 5516 var Component = workInProgress.type; 5517 if (isContextProvider(Component)) { 5518 pushContextProvider(workInProgress); 5519 } 5520 break; 5521 } 5522 case HostPortal: 5523 pushHostContainer(workInProgress, workInProgress.stateNode.containerInfo); 5524 break; 5525 case ContextProvider: 5526 { 5527 var newValue = workInProgress.memoizedProps.value; 5528 pushProvider(workInProgress, newValue); 5529 break; 5530 } 5531 case Profiler: 5532 if (enableProfilerTimer) { 5533 workInProgress.effectTag |= Update; 5534 } 5535 break; 5536 case SuspenseComponent: 5537 { 5538 var state = workInProgress.memoizedState; 5539 var didTimeout = state !== null; 5540 if (didTimeout) { 5541 // If this boundary is currently timed out, we need to decide 5542 // whether to retry the primary children, or to skip over it and 5543 // go straight to the fallback. Check the priority of the primary 5544 var primaryChildFragment = workInProgress.child; 5545 var primaryChildExpirationTime = primaryChildFragment.childExpirationTime; 5546 if (primaryChildExpirationTime !== NoWork && primaryChildExpirationTime >= renderExpirationTime) { 5547 // The primary children have pending work. Use the normal path 5548 // to attempt to render the primary children again. 5549 return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); 5550 } else { 5551 // The primary children do not have pending work with sufficient 5552 // priority. Bailout. 5553 var child = bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 5554 if (child !== null) { 5555 // The fallback children have pending work. Skip over the 5556 // primary children and work on the fallback. 5557 return child.sibling; 5558 } else { 5559 return null; 5560 } 5561 } 5562 } 5563 break; 5564 } 5565 case DehydratedSuspenseComponent: 5566 { 5567 if (enableSuspenseServerRenderer) { 5568 // We know that this component will suspend again because if it has 5569 // been unsuspended it has committed as a regular Suspense component. 5570 // If it needs to be retried, it should have work scheduled on it. 5571 workInProgress.effectTag |= DidCapture; 5572 break; 5573 } 5574 } 5575 } 5576 return bailoutOnAlreadyFinishedWork(current$$1, workInProgress, renderExpirationTime); 5577 } 5578 } else { 5579 didReceiveUpdate = false; 5580 } 5581 5582 // Before entering the begin phase, clear the expiration time. 5583 workInProgress.expirationTime = NoWork; 5584 5585 switch (workInProgress.tag) { 5586 case IndeterminateComponent: 5587 { 5588 var elementType = workInProgress.elementType; 5589 return mountIndeterminateComponent(current$$1, workInProgress, elementType, renderExpirationTime); 5590 } 5591 case LazyComponent: 5592 { 5593 var _elementType = workInProgress.elementType; 5594 return mountLazyComponent(current$$1, workInProgress, _elementType, updateExpirationTime, renderExpirationTime); 5595 } 5596 case FunctionComponent: 5597 { 5598 var _Component = workInProgress.type; 5599 var unresolvedProps = workInProgress.pendingProps; 5600 var resolvedProps = workInProgress.elementType === _Component ? unresolvedProps : resolveDefaultProps(_Component, unresolvedProps); 5601 return updateFunctionComponent(current$$1, workInProgress, _Component, resolvedProps, renderExpirationTime); 5602 } 5603 case ClassComponent: 5604 { 5605 var _Component2 = workInProgress.type; 5606 var _unresolvedProps = workInProgress.pendingProps; 5607 var _resolvedProps = workInProgress.elementType === _Component2 ? _unresolvedProps : resolveDefaultProps(_Component2, _unresolvedProps); 5608 return updateClassComponent(current$$1, workInProgress, _Component2, _resolvedProps, renderExpirationTime); 5609 } 5610 case HostRoot: 5611 return updateHostRoot(current$$1, workInProgress, renderExpirationTime); 5612 case HostComponent: 5613 return updateHostComponent(current$$1, workInProgress, renderExpirationTime); 5614 case HostText: 5615 return updateHostText(current$$1, workInProgress); 5616 case SuspenseComponent: 5617 return updateSuspenseComponent(current$$1, workInProgress, renderExpirationTime); 5618 case HostPortal: 5619 return updatePortalComponent(current$$1, workInProgress, renderExpirationTime); 5620 case ForwardRef: 5621 { 5622 var type = workInProgress.type; 5623 var _unresolvedProps2 = workInProgress.pendingProps; 5624 var _resolvedProps2 = workInProgress.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2); 5625 return updateForwardRef(current$$1, workInProgress, type, _resolvedProps2, renderExpirationTime); 5626 } 5627 case Fragment: 5628 return updateFragment(current$$1, workInProgress, renderExpirationTime); 5629 case Mode: 5630 return updateMode(current$$1, workInProgress, renderExpirationTime); 5631 case Profiler: 5632 return updateProfiler(current$$1, workInProgress, renderExpirationTime); 5633 case ContextProvider: 5634 return updateContextProvider(current$$1, workInProgress, renderExpirationTime); 5635 case ContextConsumer: 5636 return updateContextConsumer(current$$1, workInProgress, renderExpirationTime); 5637 case MemoComponent: 5638 { 5639 var _type2 = workInProgress.type; 5640 var _unresolvedProps3 = workInProgress.pendingProps; 5641 // Resolve outer props first, then resolve inner props. 5642 var _resolvedProps3 = resolveDefaultProps(_type2, _unresolvedProps3); 5643 _resolvedProps3 = resolveDefaultProps(_type2.type, _resolvedProps3); 5644 return updateMemoComponent(current$$1, workInProgress, _type2, _resolvedProps3, updateExpirationTime, renderExpirationTime); 5645 } 5646 case SimpleMemoComponent: 5647 { 5648 return updateSimpleMemoComponent(current$$1, workInProgress, workInProgress.type, workInProgress.pendingProps, updateExpirationTime, renderExpirationTime); 5649 } 5650 case IncompleteClassComponent: 5651 { 5652 var _Component3 = workInProgress.type; 5653 var _unresolvedProps4 = workInProgress.pendingProps; 5654 var _resolvedProps4 = workInProgress.elementType === _Component3 ? _unresolvedProps4 : resolveDefaultProps(_Component3, _unresolvedProps4); 5655 return mountIncompleteClassComponent(current$$1, workInProgress, _Component3, _resolvedProps4, renderExpirationTime); 5656 } 5657 case DehydratedSuspenseComponent: 5658 { 5659 if (enableSuspenseServerRenderer) { 5660 return updateDehydratedSuspenseComponent(current$$1, workInProgress, renderExpirationTime); 5661 } 5662 break; 5663 } 5664 } 5665 reactProdInvariant('156'); 5666 } 5667 5668 var valueCursor = createCursor(null); 5669 5670 var currentlyRenderingFiber = null; 5671 var lastContextDependency = null; 5672 var lastContextWithAllBitsObserved = null; 5673 5674 function resetContextDependences() { 5675 // This is called right before React yields execution, to ensure `readContext` 5676 // cannot be called outside the render phase. 5677 currentlyRenderingFiber = null; 5678 lastContextDependency = null; 5679 lastContextWithAllBitsObserved = null; 5680 5681 } 5682 5683 5684 5685 5686 5687 function pushProvider(providerFiber, nextValue) { 5688 var context = providerFiber.type._context; 5689 5690 if (isPrimaryRenderer) { 5691 push(valueCursor, context._currentValue, providerFiber); 5692 5693 context._currentValue = nextValue; 5694 5695 } else { 5696 push(valueCursor, context._currentValue2, providerFiber); 5697 5698 context._currentValue2 = nextValue; 5699 5700 } 5701 } 5702 5703 function popProvider(providerFiber) { 5704 var currentValue = valueCursor.current; 5705 5706 pop(valueCursor, providerFiber); 5707 5708 var context = providerFiber.type._context; 5709 if (isPrimaryRenderer) { 5710 context._currentValue = currentValue; 5711 } else { 5712 context._currentValue2 = currentValue; 5713 } 5714 } 5715 5716 function calculateChangedBits(context, newValue, oldValue) { 5717 if (is(oldValue, newValue)) { 5718 // No change 5719 return 0; 5720 } else { 5721 var changedBits = typeof context._calculateChangedBits === 'function' ? context._calculateChangedBits(oldValue, newValue) : maxSigned31BitInt; 5722 5723 return changedBits | 0; 5724 } 5725 } 5726 5727 function scheduleWorkOnParentPath(parent, renderExpirationTime) { 5728 // Update the child expiration time of all the ancestors, including 5729 // the alternates. 5730 var node = parent; 5731 while (node !== null) { 5732 var alternate = node.alternate; 5733 if (node.childExpirationTime < renderExpirationTime) { 5734 node.childExpirationTime = renderExpirationTime; 5735 if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { 5736 alternate.childExpirationTime = renderExpirationTime; 5737 } 5738 } else if (alternate !== null && alternate.childExpirationTime < renderExpirationTime) { 5739 alternate.childExpirationTime = renderExpirationTime; 5740 } else { 5741 // Neither alternate was updated, which means the rest of the 5742 // ancestor path already has sufficient priority. 5743 break; 5744 } 5745 node = node.return; 5746 } 5747 } 5748 5749 function propagateContextChange(workInProgress, context, changedBits, renderExpirationTime) { 5750 var fiber = workInProgress.child; 5751 if (fiber !== null) { 5752 // Set the return pointer of the child to the work-in-progress fiber. 5753 fiber.return = workInProgress; 5754 } 5755 while (fiber !== null) { 5756 var nextFiber = void 0; 5757 5758 // Visit this fiber. 5759 var list = fiber.contextDependencies; 5760 if (list !== null) { 5761 nextFiber = fiber.child; 5762 5763 var dependency = list.first; 5764 while (dependency !== null) { 5765 // Check if the context matches. 5766 if (dependency.context === context && (dependency.observedBits & changedBits) !== 0) { 5767 // Match! Schedule an update on this fiber. 5768 5769 if (fiber.tag === ClassComponent) { 5770 // Schedule a force update on the work-in-progress. 5771 var update = createUpdate(renderExpirationTime); 5772 update.tag = ForceUpdate; 5773 // TODO: Because we don't have a work-in-progress, this will add the 5774 // update to the current fiber, too, which means it will persist even if 5775 // this render is thrown away. Since it's a race condition, not sure it's 5776 // worth fixing. 5777 enqueueUpdate(fiber, update); 5778 } 5779 5780 if (fiber.expirationTime < renderExpirationTime) { 5781 fiber.expirationTime = renderExpirationTime; 5782 } 5783 var alternate = fiber.alternate; 5784 if (alternate !== null && alternate.expirationTime < renderExpirationTime) { 5785 alternate.expirationTime = renderExpirationTime; 5786 } 5787 5788 scheduleWorkOnParentPath(fiber.return, renderExpirationTime); 5789 5790 // Mark the expiration time on the list, too. 5791 if (list.expirationTime < renderExpirationTime) { 5792 list.expirationTime = renderExpirationTime; 5793 } 5794 5795 // Since we already found a match, we can stop traversing the 5796 // dependency list. 5797 break; 5798 } 5799 dependency = dependency.next; 5800 } 5801 } else if (fiber.tag === ContextProvider) { 5802 // Don't scan deeper if this is a matching provider 5803 nextFiber = fiber.type === workInProgress.type ? null : fiber.child; 5804 } else if (enableSuspenseServerRenderer && fiber.tag === DehydratedSuspenseComponent) { 5805 // If a dehydrated suspense component is in this subtree, we don't know 5806 // if it will have any context consumers in it. The best we can do is 5807 // mark it as having updates on its children. 5808 if (fiber.expirationTime < renderExpirationTime) { 5809 fiber.expirationTime = renderExpirationTime; 5810 } 5811 var _alternate = fiber.alternate; 5812 if (_alternate !== null && _alternate.expirationTime < renderExpirationTime) { 5813 _alternate.expirationTime = renderExpirationTime; 5814 } 5815 // This is intentionally passing this fiber as the parent 5816 // because we want to schedule this fiber as having work 5817 // on its children. We'll use the childExpirationTime on 5818 // this fiber to indicate that a context has changed. 5819 scheduleWorkOnParentPath(fiber, renderExpirationTime); 5820 nextFiber = fiber.sibling; 5821 } else { 5822 // Traverse down. 5823 nextFiber = fiber.child; 5824 } 5825 5826 if (nextFiber !== null) { 5827 // Set the return pointer of the child to the work-in-progress fiber. 5828 nextFiber.return = fiber; 5829 } else { 5830 // No child. Traverse to next sibling. 5831 nextFiber = fiber; 5832 while (nextFiber !== null) { 5833 if (nextFiber === workInProgress) { 5834 // We're back to the root of this subtree. Exit. 5835 nextFiber = null; 5836 break; 5837 } 5838 var sibling = nextFiber.sibling; 5839 if (sibling !== null) { 5840 // Set the return pointer of the sibling to the work-in-progress fiber. 5841 sibling.return = nextFiber.return; 5842 nextFiber = sibling; 5843 break; 5844 } 5845 // No more siblings. Traverse up. 5846 nextFiber = nextFiber.return; 5847 } 5848 } 5849 fiber = nextFiber; 5850 } 5851 } 5852 5853 function prepareToReadContext(workInProgress, renderExpirationTime) { 5854 currentlyRenderingFiber = workInProgress; 5855 lastContextDependency = null; 5856 lastContextWithAllBitsObserved = null; 5857 5858 var currentDependencies = workInProgress.contextDependencies; 5859 if (currentDependencies !== null && currentDependencies.expirationTime >= renderExpirationTime) { 5860 // Context list has a pending update. Mark that this fiber performed work. 5861 markWorkInProgressReceivedUpdate(); 5862 } 5863 5864 // Reset the work-in-progress list 5865 workInProgress.contextDependencies = null; 5866 } 5867 5868 function readContext(context, observedBits) { 5869 if (lastContextWithAllBitsObserved === context) { 5870 // Nothing to do. We already observe everything in this context. 5871 } else if (observedBits === false || observedBits === 0) { 5872 // Do not observe any updates. 5873 } else { 5874 var resolvedObservedBits = void 0; // Avoid deopting on observable arguments or heterogeneous types. 5875 if (typeof observedBits !== 'number' || observedBits === maxSigned31BitInt) { 5876 // Observe all updates. 5877 lastContextWithAllBitsObserved = context; 5878 resolvedObservedBits = maxSigned31BitInt; 5879 } else { 5880 resolvedObservedBits = observedBits; 5881 } 5882 5883 var contextItem = { 5884 context: context, 5885 observedBits: resolvedObservedBits, 5886 next: null 5887 }; 5888 5889 if (lastContextDependency === null) { 5890 !(currentlyRenderingFiber !== null) ? reactProdInvariant('308') : void 0; 5891 5892 // This is the first dependency for this component. Create a new list. 5893 lastContextDependency = contextItem; 5894 currentlyRenderingFiber.contextDependencies = { 5895 first: contextItem, 5896 expirationTime: NoWork 5897 }; 5898 } else { 5899 // Append a new context item. 5900 lastContextDependency = lastContextDependency.next = contextItem; 5901 } 5902 } 5903 return isPrimaryRenderer ? context._currentValue : context._currentValue2; 5904 } 5905 5906 // UpdateQueue is a linked list of prioritized updates. 5907 // 5908 // Like fibers, update queues come in pairs: a current queue, which represents 5909 // the visible state of the screen, and a work-in-progress queue, which can be 5910 // mutated and processed asynchronously before it is committed — a form of 5911 // double buffering. If a work-in-progress render is discarded before finishing, 5912 // we create a new work-in-progress by cloning the current queue. 5913 // 5914 // Both queues share a persistent, singly-linked list structure. To schedule an 5915 // update, we append it to the end of both queues. Each queue maintains a 5916 // pointer to first update in the persistent list that hasn't been processed. 5917 // The work-in-progress pointer always has a position equal to or greater than 5918 // the current queue, since we always work on that one. The current queue's 5919 // pointer is only updated during the commit phase, when we swap in the 5920 // work-in-progress. 5921 // 5922 // For example: 5923 // 5924 // Current pointer: A - B - C - D - E - F 5925 // Work-in-progress pointer: D - E - F 5926 // ^ 5927 // The work-in-progress queue has 5928 // processed more updates than current. 5929 // 5930 // The reason we append to both queues is because otherwise we might drop 5931 // updates without ever processing them. For example, if we only add updates to 5932 // the work-in-progress queue, some updates could be lost whenever a work-in 5933 // -progress render restarts by cloning from current. Similarly, if we only add 5934 // updates to the current queue, the updates will be lost whenever an already 5935 // in-progress queue commits and swaps with the current queue. However, by 5936 // adding to both queues, we guarantee that the update will be part of the next 5937 // work-in-progress. (And because the work-in-progress queue becomes the 5938 // current queue once it commits, there's no danger of applying the same 5939 // update twice.) 5940 // 5941 // Prioritization 5942 // -------------- 5943 // 5944 // Updates are not sorted by priority, but by insertion; new updates are always 5945 // appended to the end of the list. 5946 // 5947 // The priority is still important, though. When processing the update queue 5948 // during the render phase, only the updates with sufficient priority are 5949 // included in the result. If we skip an update because it has insufficient 5950 // priority, it remains in the queue to be processed later, during a lower 5951 // priority render. Crucially, all updates subsequent to a skipped update also 5952 // remain in the queue *regardless of their priority*. That means high priority 5953 // updates are sometimes processed twice, at two separate priorities. We also 5954 // keep track of a base state, that represents the state before the first 5955 // update in the queue is applied. 5956 // 5957 // For example: 5958 // 5959 // Given a base state of '', and the following queue of updates 5960 // 5961 // A1 - B2 - C1 - D2 5962 // 5963 // where the number indicates the priority, and the update is applied to the 5964 // previous state by appending a letter, React will process these updates as 5965 // two separate renders, one per distinct priority level: 5966 // 5967 // First render, at priority 1: 5968 // Base state: '' 5969 // Updates: [A1, C1] 5970 // Result state: 'AC' 5971 // 5972 // Second render, at priority 2: 5973 // Base state: 'A' <- The base state does not include C1, 5974 // because B2 was skipped. 5975 // Updates: [B2, C1, D2] <- C1 was rebased on top of B2 5976 // Result state: 'ABCD' 5977 // 5978 // Because we process updates in insertion order, and rebase high priority 5979 // updates when preceding updates are skipped, the final result is deterministic 5980 // regardless of priority. Intermediate state may vary according to system 5981 // resources, but the final state is always the same. 5982 5983 var UpdateState = 0; 5984 var ReplaceState = 1; 5985 var ForceUpdate = 2; 5986 var CaptureUpdate = 3; 5987 5988 // Global state that is reset at the beginning of calling `processUpdateQueue`. 5989 // It should only be read right after calling `processUpdateQueue`, via 5990 // `checkHasForceUpdateAfterProcessing`. 5991 var hasForceUpdate = false; 5992 5993 5994 function createUpdateQueue(baseState) { 5995 var queue = { 5996 baseState: baseState, 5997 firstUpdate: null, 5998 lastUpdate: null, 5999 firstCapturedUpdate: null, 6000 lastCapturedUpdate: null, 6001 firstEffect: null, 6002 lastEffect: null, 6003 firstCapturedEffect: null, 6004 lastCapturedEffect: null 6005 }; 6006 return queue; 6007 } 6008 6009 function cloneUpdateQueue(currentQueue) { 6010 var queue = { 6011 baseState: currentQueue.baseState, 6012 firstUpdate: currentQueue.firstUpdate, 6013 lastUpdate: currentQueue.lastUpdate, 6014 6015 // TODO: With resuming, if we bail out and resuse the child tree, we should 6016 // keep these effects. 6017 firstCapturedUpdate: null, 6018 lastCapturedUpdate: null, 6019 6020 firstEffect: null, 6021 lastEffect: null, 6022 6023 firstCapturedEffect: null, 6024 lastCapturedEffect: null 6025 }; 6026 return queue; 6027 } 6028 6029 function createUpdate(expirationTime) { 6030 return { 6031 expirationTime: expirationTime, 6032 6033 tag: UpdateState, 6034 payload: null, 6035 callback: null, 6036 6037 next: null, 6038 nextEffect: null 6039 }; 6040 } 6041 6042 function appendUpdateToQueue(queue, update) { 6043 // Append the update to the end of the list. 6044 if (queue.lastUpdate === null) { 6045 // Queue is empty 6046 queue.firstUpdate = queue.lastUpdate = update; 6047 } else { 6048 queue.lastUpdate.next = update; 6049 queue.lastUpdate = update; 6050 } 6051 } 6052 6053 function enqueueUpdate(fiber, update) { 6054 // Update queues are created lazily. 6055 var alternate = fiber.alternate; 6056 var queue1 = void 0; 6057 var queue2 = void 0; 6058 if (alternate === null) { 6059 // There's only one fiber. 6060 queue1 = fiber.updateQueue; 6061 queue2 = null; 6062 if (queue1 === null) { 6063 queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); 6064 } 6065 } else { 6066 // There are two owners. 6067 queue1 = fiber.updateQueue; 6068 queue2 = alternate.updateQueue; 6069 if (queue1 === null) { 6070 if (queue2 === null) { 6071 // Neither fiber has an update queue. Create new ones. 6072 queue1 = fiber.updateQueue = createUpdateQueue(fiber.memoizedState); 6073 queue2 = alternate.updateQueue = createUpdateQueue(alternate.memoizedState); 6074 } else { 6075 // Only one fiber has an update queue. Clone to create a new one. 6076 queue1 = fiber.updateQueue = cloneUpdateQueue(queue2); 6077 } 6078 } else { 6079 if (queue2 === null) { 6080 // Only one fiber has an update queue. Clone to create a new one. 6081 queue2 = alternate.updateQueue = cloneUpdateQueue(queue1); 6082 } else { 6083 // Both owners have an update queue. 6084 } 6085 } 6086 } 6087 if (queue2 === null || queue1 === queue2) { 6088 // There's only a single queue. 6089 appendUpdateToQueue(queue1, update); 6090 } else { 6091 // There are two queues. We need to append the update to both queues, 6092 // while accounting for the persistent structure of the list — we don't 6093 // want the same update to be added multiple times. 6094 if (queue1.lastUpdate === null || queue2.lastUpdate === null) { 6095 // One of the queues is not empty. We must add the update to both queues. 6096 appendUpdateToQueue(queue1, update); 6097 appendUpdateToQueue(queue2, update); 6098 } else { 6099 // Both queues are non-empty. The last update is the same in both lists, 6100 // because of structural sharing. So, only append to one of the lists. 6101 appendUpdateToQueue(queue1, update); 6102 // But we still need to update the `lastUpdate` pointer of queue2. 6103 queue2.lastUpdate = update; 6104 } 6105 } 6106 6107 6108 } 6109 6110 function enqueueCapturedUpdate(workInProgress, update) { 6111 // Captured updates go into a separate list, and only on the work-in- 6112 // progress queue. 6113 var workInProgressQueue = workInProgress.updateQueue; 6114 if (workInProgressQueue === null) { 6115 workInProgressQueue = workInProgress.updateQueue = createUpdateQueue(workInProgress.memoizedState); 6116 } else { 6117 // TODO: I put this here rather than createWorkInProgress so that we don't 6118 // clone the queue unnecessarily. There's probably a better way to 6119 // structure this. 6120 workInProgressQueue = ensureWorkInProgressQueueIsAClone(workInProgress, workInProgressQueue); 6121 } 6122 6123 // Append the update to the end of the list. 6124 if (workInProgressQueue.lastCapturedUpdate === null) { 6125 // This is the first render phase update 6126 workInProgressQueue.firstCapturedUpdate = workInProgressQueue.lastCapturedUpdate = update; 6127 } else { 6128 workInProgressQueue.lastCapturedUpdate.next = update; 6129 workInProgressQueue.lastCapturedUpdate = update; 6130 } 6131 } 6132 6133 function ensureWorkInProgressQueueIsAClone(workInProgress, queue) { 6134 var current = workInProgress.alternate; 6135 if (current !== null) { 6136 // If the work-in-progress queue is equal to the current queue, 6137 // we need to clone it first. 6138 if (queue === current.updateQueue) { 6139 queue = workInProgress.updateQueue = cloneUpdateQueue(queue); 6140 } 6141 } 6142 return queue; 6143 } 6144 6145 function getStateFromUpdate(workInProgress, queue, update, prevState, nextProps, instance) { 6146 switch (update.tag) { 6147 case ReplaceState: 6148 { 6149 var _payload = update.payload; 6150 if (typeof _payload === 'function') { 6151 // Updater function 6152 var nextState = _payload.call(instance, prevState, nextProps); 6153 return nextState; 6154 } 6155 // State object 6156 return _payload; 6157 } 6158 case CaptureUpdate: 6159 { 6160 workInProgress.effectTag = workInProgress.effectTag & ~ShouldCapture | DidCapture; 6161 } 6162 // Intentional fallthrough 6163 case UpdateState: 6164 { 6165 var _payload2 = update.payload; 6166 var partialState = void 0; 6167 if (typeof _payload2 === 'function') { 6168 // Updater function 6169 partialState = _payload2.call(instance, prevState, nextProps); 6170 6171 } else { 6172 // Partial state object 6173 partialState = _payload2; 6174 } 6175 if (partialState === null || partialState === undefined) { 6176 // Null and undefined are treated as no-ops. 6177 return prevState; 6178 } 6179 // Merge the partial state and the previous state. 6180 return _assign({}, prevState, partialState); 6181 } 6182 case ForceUpdate: 6183 { 6184 hasForceUpdate = true; 6185 return prevState; 6186 } 6187 } 6188 return prevState; 6189 } 6190 6191 function processUpdateQueue(workInProgress, queue, props, instance, renderExpirationTime) { 6192 hasForceUpdate = false; 6193 6194 queue = ensureWorkInProgressQueueIsAClone(workInProgress, queue); 6195 6196 var newBaseState = queue.baseState; 6197 var newFirstUpdate = null; 6198 var newExpirationTime = NoWork; 6199 6200 // Iterate through the list of updates to compute the result. 6201 var update = queue.firstUpdate; 6202 var resultState = newBaseState; 6203 while (update !== null) { 6204 var updateExpirationTime = update.expirationTime; 6205 if (updateExpirationTime < renderExpirationTime) { 6206 // This update does not have sufficient priority. Skip it. 6207 if (newFirstUpdate === null) { 6208 // This is the first skipped update. It will be the first update in 6209 // the new list. 6210 newFirstUpdate = update; 6211 // Since this is the first update that was skipped, the current result 6212 // is the new base state. 6213 newBaseState = resultState; 6214 } 6215 // Since this update will remain in the list, update the remaining 6216 // expiration time. 6217 if (newExpirationTime < updateExpirationTime) { 6218 newExpirationTime = updateExpirationTime; 6219 } 6220 } else { 6221 // This update does have sufficient priority. Process it and compute 6222 // a new result. 6223 resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); 6224 var _callback = update.callback; 6225 if (_callback !== null) { 6226 workInProgress.effectTag |= Callback; 6227 // Set this to null, in case it was mutated during an aborted render. 6228 update.nextEffect = null; 6229 if (queue.lastEffect === null) { 6230 queue.firstEffect = queue.lastEffect = update; 6231 } else { 6232 queue.lastEffect.nextEffect = update; 6233 queue.lastEffect = update; 6234 } 6235 } 6236 } 6237 // Continue to the next update. 6238 update = update.next; 6239 } 6240 6241 // Separately, iterate though the list of captured updates. 6242 var newFirstCapturedUpdate = null; 6243 update = queue.firstCapturedUpdate; 6244 while (update !== null) { 6245 var _updateExpirationTime = update.expirationTime; 6246 if (_updateExpirationTime < renderExpirationTime) { 6247 // This update does not have sufficient priority. Skip it. 6248 if (newFirstCapturedUpdate === null) { 6249 // This is the first skipped captured update. It will be the first 6250 // update in the new list. 6251 newFirstCapturedUpdate = update; 6252 // If this is the first update that was skipped, the current result is 6253 // the new base state. 6254 if (newFirstUpdate === null) { 6255 newBaseState = resultState; 6256 } 6257 } 6258 // Since this update will remain in the list, update the remaining 6259 // expiration time. 6260 if (newExpirationTime < _updateExpirationTime) { 6261 newExpirationTime = _updateExpirationTime; 6262 } 6263 } else { 6264 // This update does have sufficient priority. Process it and compute 6265 // a new result. 6266 resultState = getStateFromUpdate(workInProgress, queue, update, resultState, props, instance); 6267 var _callback2 = update.callback; 6268 if (_callback2 !== null) { 6269 workInProgress.effectTag |= Callback; 6270 // Set this to null, in case it was mutated during an aborted render. 6271 update.nextEffect = null; 6272 if (queue.lastCapturedEffect === null) { 6273 queue.firstCapturedEffect = queue.lastCapturedEffect = update; 6274 } else { 6275 queue.lastCapturedEffect.nextEffect = update; 6276 queue.lastCapturedEffect = update; 6277 } 6278 } 6279 } 6280 update = update.next; 6281 } 6282 6283 if (newFirstUpdate === null) { 6284 queue.lastUpdate = null; 6285 } 6286 if (newFirstCapturedUpdate === null) { 6287 queue.lastCapturedUpdate = null; 6288 } else { 6289 workInProgress.effectTag |= Callback; 6290 } 6291 if (newFirstUpdate === null && newFirstCapturedUpdate === null) { 6292 // We processed every update, without skipping. That means the new base 6293 // state is the same as the result state. 6294 newBaseState = resultState; 6295 } 6296 6297 queue.baseState = newBaseState; 6298 queue.firstUpdate = newFirstUpdate; 6299 queue.firstCapturedUpdate = newFirstCapturedUpdate; 6300 6301 // Set the remaining expiration time to be whatever is remaining in the queue. 6302 // This should be fine because the only two other things that contribute to 6303 // expiration time are props and context. We're already in the middle of the 6304 // begin phase by the time we start processing the queue, so we've already 6305 // dealt with the props. Context in components that specify 6306 // shouldComponentUpdate is tricky; but we'll have to account for 6307 // that regardless. 6308 workInProgress.expirationTime = newExpirationTime; 6309 workInProgress.memoizedState = resultState; 6310 6311 6312 } 6313 6314 function callCallback(callback, context) { 6315 !(typeof callback === 'function') ? reactProdInvariant('191', callback) : void 0; 6316 callback.call(context); 6317 } 6318 6319 function resetHasForceUpdateBeforeProcessing() { 6320 hasForceUpdate = false; 6321 } 6322 6323 function checkHasForceUpdateAfterProcessing() { 6324 return hasForceUpdate; 6325 } 6326 6327 function commitUpdateQueue(finishedWork, finishedQueue, instance, renderExpirationTime) { 6328 // If the finished render included captured updates, and there are still 6329 // lower priority updates left over, we need to keep the captured updates 6330 // in the queue so that they are rebased and not dropped once we process the 6331 // queue again at the lower priority. 6332 if (finishedQueue.firstCapturedUpdate !== null) { 6333 // Join the captured update list to the end of the normal list. 6334 if (finishedQueue.lastUpdate !== null) { 6335 finishedQueue.lastUpdate.next = finishedQueue.firstCapturedUpdate; 6336 finishedQueue.lastUpdate = finishedQueue.lastCapturedUpdate; 6337 } 6338 // Clear the list of captured updates. 6339 finishedQueue.firstCapturedUpdate = finishedQueue.lastCapturedUpdate = null; 6340 } 6341 6342 // Commit the effects 6343 commitUpdateEffects(finishedQueue.firstEffect, instance); 6344 finishedQueue.firstEffect = finishedQueue.lastEffect = null; 6345 6346 commitUpdateEffects(finishedQueue.firstCapturedEffect, instance); 6347 finishedQueue.firstCapturedEffect = finishedQueue.lastCapturedEffect = null; 6348 } 6349 6350 function commitUpdateEffects(effect, instance) { 6351 while (effect !== null) { 6352 var _callback3 = effect.callback; 6353 if (_callback3 !== null) { 6354 effect.callback = null; 6355 callCallback(_callback3, instance); 6356 } 6357 effect = effect.nextEffect; 6358 } 6359 } 6360 6361 function createCapturedValue(value, source) { 6362 // If the value is an error, call this function immediately after it is thrown 6363 // so the stack is accurate. 6364 return { 6365 value: value, 6366 source: source, 6367 stack: getStackByFiberInDevAndProd(source) 6368 }; 6369 } 6370 6371 function markUpdate(workInProgress) { 6372 // Tag the fiber with an update effect. This turns a Placement into 6373 // a PlacementAndUpdate. 6374 workInProgress.effectTag |= Update; 6375 } 6376 6377 function markRef$1(workInProgress) { 6378 workInProgress.effectTag |= Ref; 6379 } 6380 6381 var appendAllChildren = void 0; 6382 var updateHostContainer = void 0; 6383 var updateHostComponent$1 = void 0; 6384 var updateHostText$1 = void 0; 6385 if (supportsMutation) { 6386 // Mutation mode 6387 6388 appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) { 6389 // We only have the top Fiber that was created but we need recurse down its 6390 // children to find all the terminal nodes. 6391 var node = workInProgress.child; 6392 while (node !== null) { 6393 if (node.tag === HostComponent || node.tag === HostText) { 6394 appendInitialChild(parent, node.stateNode); 6395 } else if (node.tag === HostPortal) { 6396 // If we have a portal child, then we don't want to traverse 6397 // down its children. Instead, we'll get insertions from each child in 6398 // the portal directly. 6399 } else if (node.child !== null) { 6400 node.child.return = node; 6401 node = node.child; 6402 continue; 6403 } 6404 if (node === workInProgress) { 6405 return; 6406 } 6407 while (node.sibling === null) { 6408 if (node.return === null || node.return === workInProgress) { 6409 return; 6410 } 6411 node = node.return; 6412 } 6413 node.sibling.return = node.return; 6414 node = node.sibling; 6415 } 6416 }; 6417 6418 updateHostContainer = function (workInProgress) { 6419 // Noop 6420 }; 6421 updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 6422 // If we have an alternate, that means this is an update and we need to 6423 // schedule a side-effect to do the updates. 6424 var oldProps = current.memoizedProps; 6425 if (oldProps === newProps) { 6426 // In mutation mode, this is sufficient for a bailout because 6427 // we won't touch this node even if children changed. 6428 return; 6429 } 6430 6431 // If we get updated because one of our children updated, we don't 6432 // have newProps so we'll have to reuse them. 6433 // TODO: Split the update API as separate for the props vs. children. 6434 // Even better would be if children weren't special cased at all tho. 6435 var instance = workInProgress.stateNode; 6436 var currentHostContext = getHostContext(); 6437 // TODO: Experiencing an error where oldProps is null. Suggests a host 6438 // component is hitting the resume path. Figure out why. Possibly 6439 // related to `hidden`. 6440 var updatePayload = prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, currentHostContext); 6441 // TODO: Type this specific to this type of component. 6442 workInProgress.updateQueue = updatePayload; 6443 // If the update payload indicates that there is a change or if there 6444 // is a new ref we mark this as an update. All the work is done in commitWork. 6445 if (updatePayload) { 6446 markUpdate(workInProgress); 6447 } 6448 }; 6449 updateHostText$1 = function (current, workInProgress, oldText, newText) { 6450 // If the text differs, mark it as an update. All the work in done in commitWork. 6451 if (oldText !== newText) { 6452 markUpdate(workInProgress); 6453 } 6454 }; 6455 } else if (supportsPersistence) { 6456 // Persistent host tree mode 6457 6458 appendAllChildren = function (parent, workInProgress, needsVisibilityToggle, isHidden) { 6459 // We only have the top Fiber that was created but we need recurse down its 6460 // children to find all the terminal nodes. 6461 var node = workInProgress.child; 6462 while (node !== null) { 6463 // eslint-disable-next-line no-labels 6464 branches: if (node.tag === HostComponent) { 6465 var instance = node.stateNode; 6466 if (needsVisibilityToggle) { 6467 var props = node.memoizedProps; 6468 var type = node.type; 6469 if (isHidden) { 6470 // This child is inside a timed out tree. Hide it. 6471 instance = cloneHiddenInstance(instance, type, props, node); 6472 } else { 6473 // This child was previously inside a timed out tree. If it was not 6474 // updated during this render, it may need to be unhidden. Clone 6475 // again to be sure. 6476 instance = cloneUnhiddenInstance(instance, type, props, node); 6477 } 6478 node.stateNode = instance; 6479 } 6480 appendInitialChild(parent, instance); 6481 } else if (node.tag === HostText) { 6482 var _instance = node.stateNode; 6483 if (needsVisibilityToggle) { 6484 var text = node.memoizedProps; 6485 var rootContainerInstance = getRootHostContainer(); 6486 var currentHostContext = getHostContext(); 6487 if (isHidden) { 6488 _instance = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 6489 } else { 6490 _instance = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 6491 } 6492 node.stateNode = _instance; 6493 } 6494 appendInitialChild(parent, _instance); 6495 } else if (node.tag === HostPortal) { 6496 // If we have a portal child, then we don't want to traverse 6497 // down its children. Instead, we'll get insertions from each child in 6498 // the portal directly. 6499 } else if (node.tag === SuspenseComponent) { 6500 var current = node.alternate; 6501 if (current !== null) { 6502 var oldState = current.memoizedState; 6503 var newState = node.memoizedState; 6504 var oldIsHidden = oldState !== null; 6505 var newIsHidden = newState !== null; 6506 if (oldIsHidden !== newIsHidden) { 6507 // The placeholder either just timed out or switched back to the normal 6508 // children after having previously timed out. Toggle the visibility of 6509 // the direct host children. 6510 var primaryChildParent = newIsHidden ? node.child : node; 6511 if (primaryChildParent !== null) { 6512 appendAllChildren(parent, primaryChildParent, true, newIsHidden); 6513 } 6514 // eslint-disable-next-line no-labels 6515 break branches; 6516 } 6517 } 6518 if (node.child !== null) { 6519 // Continue traversing like normal 6520 node.child.return = node; 6521 node = node.child; 6522 continue; 6523 } 6524 } else if (node.child !== null) { 6525 node.child.return = node; 6526 node = node.child; 6527 continue; 6528 } 6529 // $FlowFixMe This is correct but Flow is confused by the labeled break. 6530 node = node; 6531 if (node === workInProgress) { 6532 return; 6533 } 6534 while (node.sibling === null) { 6535 if (node.return === null || node.return === workInProgress) { 6536 return; 6537 } 6538 node = node.return; 6539 } 6540 node.sibling.return = node.return; 6541 node = node.sibling; 6542 } 6543 }; 6544 6545 // An unfortunate fork of appendAllChildren because we have two different parent types. 6546 var appendAllChildrenToContainer = function (containerChildSet, workInProgress, needsVisibilityToggle, isHidden) { 6547 // We only have the top Fiber that was created but we need recurse down its 6548 // children to find all the terminal nodes. 6549 var node = workInProgress.child; 6550 while (node !== null) { 6551 // eslint-disable-next-line no-labels 6552 branches: if (node.tag === HostComponent) { 6553 var instance = node.stateNode; 6554 if (needsVisibilityToggle) { 6555 var props = node.memoizedProps; 6556 var type = node.type; 6557 if (isHidden) { 6558 // This child is inside a timed out tree. Hide it. 6559 instance = cloneHiddenInstance(instance, type, props, node); 6560 } else { 6561 // This child was previously inside a timed out tree. If it was not 6562 // updated during this render, it may need to be unhidden. Clone 6563 // again to be sure. 6564 instance = cloneUnhiddenInstance(instance, type, props, node); 6565 } 6566 node.stateNode = instance; 6567 } 6568 appendChildToContainerChildSet(containerChildSet, instance); 6569 } else if (node.tag === HostText) { 6570 var _instance2 = node.stateNode; 6571 if (needsVisibilityToggle) { 6572 var text = node.memoizedProps; 6573 var rootContainerInstance = getRootHostContainer(); 6574 var currentHostContext = getHostContext(); 6575 if (isHidden) { 6576 _instance2 = createHiddenTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 6577 } else { 6578 _instance2 = createTextInstance(text, rootContainerInstance, currentHostContext, workInProgress); 6579 } 6580 node.stateNode = _instance2; 6581 } 6582 appendChildToContainerChildSet(containerChildSet, _instance2); 6583 } else if (node.tag === HostPortal) { 6584 // If we have a portal child, then we don't want to traverse 6585 // down its children. Instead, we'll get insertions from each child in 6586 // the portal directly. 6587 } else if (node.tag === SuspenseComponent) { 6588 var current = node.alternate; 6589 if (current !== null) { 6590 var oldState = current.memoizedState; 6591 var newState = node.memoizedState; 6592 var oldIsHidden = oldState !== null; 6593 var newIsHidden = newState !== null; 6594 if (oldIsHidden !== newIsHidden) { 6595 // The placeholder either just timed out or switched back to the normal 6596 // children after having previously timed out. Toggle the visibility of 6597 // the direct host children. 6598 var primaryChildParent = newIsHidden ? node.child : node; 6599 if (primaryChildParent !== null) { 6600 appendAllChildrenToContainer(containerChildSet, primaryChildParent, true, newIsHidden); 6601 } 6602 // eslint-disable-next-line no-labels 6603 break branches; 6604 } 6605 } 6606 if (node.child !== null) { 6607 // Continue traversing like normal 6608 node.child.return = node; 6609 node = node.child; 6610 continue; 6611 } 6612 } else if (node.child !== null) { 6613 node.child.return = node; 6614 node = node.child; 6615 continue; 6616 } 6617 // $FlowFixMe This is correct but Flow is confused by the labeled break. 6618 node = node; 6619 if (node === workInProgress) { 6620 return; 6621 } 6622 while (node.sibling === null) { 6623 if (node.return === null || node.return === workInProgress) { 6624 return; 6625 } 6626 node = node.return; 6627 } 6628 node.sibling.return = node.return; 6629 node = node.sibling; 6630 } 6631 }; 6632 updateHostContainer = function (workInProgress) { 6633 var portalOrRoot = workInProgress.stateNode; 6634 var childrenUnchanged = workInProgress.firstEffect === null; 6635 if (childrenUnchanged) { 6636 // No changes, just reuse the existing instance. 6637 } else { 6638 var container = portalOrRoot.containerInfo; 6639 var newChildSet = createContainerChildSet(container); 6640 // If children might have changed, we have to add them all to the set. 6641 appendAllChildrenToContainer(newChildSet, workInProgress, false, false); 6642 portalOrRoot.pendingChildren = newChildSet; 6643 // Schedule an update on the container to swap out the container. 6644 markUpdate(workInProgress); 6645 finalizeContainerChildren(container, newChildSet); 6646 } 6647 }; 6648 updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 6649 var currentInstance = current.stateNode; 6650 var oldProps = current.memoizedProps; 6651 // If there are no effects associated with this node, then none of our children had any updates. 6652 // This guarantees that we can reuse all of them. 6653 var childrenUnchanged = workInProgress.firstEffect === null; 6654 if (childrenUnchanged && oldProps === newProps) { 6655 // No changes, just reuse the existing instance. 6656 // Note that this might release a previous clone. 6657 workInProgress.stateNode = currentInstance; 6658 return; 6659 } 6660 var recyclableInstance = workInProgress.stateNode; 6661 var currentHostContext = getHostContext(); 6662 var updatePayload = null; 6663 if (oldProps !== newProps) { 6664 updatePayload = prepareUpdate(recyclableInstance, type, oldProps, newProps, rootContainerInstance, currentHostContext); 6665 } 6666 if (childrenUnchanged && updatePayload === null) { 6667 // No changes, just reuse the existing instance. 6668 // Note that this might release a previous clone. 6669 workInProgress.stateNode = currentInstance; 6670 return; 6671 } 6672 var newInstance = cloneInstance(currentInstance, updatePayload, type, oldProps, newProps, workInProgress, childrenUnchanged, recyclableInstance); 6673 if (finalizeInitialChildren(newInstance, type, newProps, rootContainerInstance, currentHostContext)) { 6674 markUpdate(workInProgress); 6675 } 6676 workInProgress.stateNode = newInstance; 6677 if (childrenUnchanged) { 6678 // If there are no other effects in this tree, we need to flag this node as having one. 6679 // Even though we're not going to use it for anything. 6680 // Otherwise parents won't know that there are new children to propagate upwards. 6681 markUpdate(workInProgress); 6682 } else { 6683 // If children might have changed, we have to add them all to the set. 6684 appendAllChildren(newInstance, workInProgress, false, false); 6685 } 6686 }; 6687 updateHostText$1 = function (current, workInProgress, oldText, newText) { 6688 if (oldText !== newText) { 6689 // If the text content differs, we'll create a new text instance for it. 6690 var rootContainerInstance = getRootHostContainer(); 6691 var currentHostContext = getHostContext(); 6692 workInProgress.stateNode = createTextInstance(newText, rootContainerInstance, currentHostContext, workInProgress); 6693 // We'll have to mark it as having an effect, even though we won't use the effect for anything. 6694 // This lets the parents know that at least one of their children has changed. 6695 markUpdate(workInProgress); 6696 } 6697 }; 6698 } else { 6699 // No host operations 6700 updateHostContainer = function (workInProgress) { 6701 // Noop 6702 }; 6703 updateHostComponent$1 = function (current, workInProgress, type, newProps, rootContainerInstance) { 6704 // Noop 6705 }; 6706 updateHostText$1 = function (current, workInProgress, oldText, newText) { 6707 // Noop 6708 }; 6709 } 6710 6711 function completeWork(current, workInProgress, renderExpirationTime) { 6712 var newProps = workInProgress.pendingProps; 6713 6714 switch (workInProgress.tag) { 6715 case IndeterminateComponent: 6716 break; 6717 case LazyComponent: 6718 break; 6719 case SimpleMemoComponent: 6720 case FunctionComponent: 6721 break; 6722 case ClassComponent: 6723 { 6724 var Component = workInProgress.type; 6725 if (isContextProvider(Component)) { 6726 popContext(workInProgress); 6727 } 6728 break; 6729 } 6730 case HostRoot: 6731 { 6732 popHostContainer(workInProgress); 6733 popTopLevelContextObject(workInProgress); 6734 var fiberRoot = workInProgress.stateNode; 6735 if (fiberRoot.pendingContext) { 6736 fiberRoot.context = fiberRoot.pendingContext; 6737 fiberRoot.pendingContext = null; 6738 } 6739 if (current === null || current.child === null) { 6740 // If we hydrated, pop so that we can delete any remaining children 6741 // that weren't hydrated. 6742 popHydrationState(workInProgress); 6743 // This resets the hacky state to fix isMounted before committing. 6744 // TODO: Delete this when we delete isMounted and findDOMNode. 6745 workInProgress.effectTag &= ~Placement; 6746 } 6747 updateHostContainer(workInProgress); 6748 break; 6749 } 6750 case HostComponent: 6751 { 6752 popHostContext(workInProgress); 6753 var rootContainerInstance = getRootHostContainer(); 6754 var type = workInProgress.type; 6755 if (current !== null && workInProgress.stateNode != null) { 6756 updateHostComponent$1(current, workInProgress, type, newProps, rootContainerInstance); 6757 6758 if (current.ref !== workInProgress.ref) { 6759 markRef$1(workInProgress); 6760 } 6761 } else { 6762 if (!newProps) { 6763 !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; 6764 // This can happen when we abort work. 6765 break; 6766 } 6767 6768 var currentHostContext = getHostContext(); 6769 // TODO: Move createInstance to beginWork and keep it on a context 6770 // "stack" as the parent. Then append children as we go in beginWork 6771 // or completeWork depending on we want to add then top->down or 6772 // bottom->up. Top->down is faster in IE11. 6773 var wasHydrated = popHydrationState(workInProgress); 6774 if (wasHydrated) { 6775 // TODO: Move this and createInstance step into the beginPhase 6776 // to consolidate. 6777 if (prepareToHydrateHostInstance(workInProgress, rootContainerInstance, currentHostContext)) { 6778 // If changes to the hydrated node needs to be applied at the 6779 // commit-phase we mark this as such. 6780 markUpdate(workInProgress); 6781 } 6782 } else { 6783 var instance = createInstance(type, newProps, rootContainerInstance, currentHostContext, workInProgress); 6784 6785 appendAllChildren(instance, workInProgress, false, false); 6786 6787 // Certain renderers require commit-time effects for initial mount. 6788 // (eg DOM renderer supports auto-focus for certain elements). 6789 // Make sure such renderers get scheduled for later work. 6790 if (finalizeInitialChildren(instance, type, newProps, rootContainerInstance, currentHostContext)) { 6791 markUpdate(workInProgress); 6792 } 6793 workInProgress.stateNode = instance; 6794 } 6795 6796 if (workInProgress.ref !== null) { 6797 // If there is a ref on a host node we need to schedule a callback 6798 markRef$1(workInProgress); 6799 } 6800 } 6801 break; 6802 } 6803 case HostText: 6804 { 6805 var newText = newProps; 6806 if (current && workInProgress.stateNode != null) { 6807 var oldText = current.memoizedProps; 6808 // If we have an alternate, that means this is an update and we need 6809 // to schedule a side-effect to do the updates. 6810 updateHostText$1(current, workInProgress, oldText, newText); 6811 } else { 6812 if (typeof newText !== 'string') { 6813 !(workInProgress.stateNode !== null) ? reactProdInvariant('166') : void 0; 6814 // This can happen when we abort work. 6815 } 6816 var _rootContainerInstance = getRootHostContainer(); 6817 var _currentHostContext = getHostContext(); 6818 var _wasHydrated = popHydrationState(workInProgress); 6819 if (_wasHydrated) { 6820 if (prepareToHydrateHostTextInstance(workInProgress)) { 6821 markUpdate(workInProgress); 6822 } 6823 } else { 6824 workInProgress.stateNode = createTextInstance(newText, _rootContainerInstance, _currentHostContext, workInProgress); 6825 } 6826 } 6827 break; 6828 } 6829 case ForwardRef: 6830 break; 6831 case SuspenseComponent: 6832 { 6833 var nextState = workInProgress.memoizedState; 6834 if ((workInProgress.effectTag & DidCapture) !== NoEffect) { 6835 // Something suspended. Re-render with the fallback children. 6836 workInProgress.expirationTime = renderExpirationTime; 6837 // Do not reset the effect list. 6838 return workInProgress; 6839 } 6840 6841 var nextDidTimeout = nextState !== null; 6842 var prevDidTimeout = current !== null && current.memoizedState !== null; 6843 6844 if (current !== null && !nextDidTimeout && prevDidTimeout) { 6845 // We just switched from the fallback to the normal children. Delete 6846 // the fallback. 6847 // TODO: Would it be better to store the fallback fragment on 6848 var currentFallbackChild = current.child.sibling; 6849 if (currentFallbackChild !== null) { 6850 // Deletions go at the beginning of the return fiber's effect list 6851 var first = workInProgress.firstEffect; 6852 if (first !== null) { 6853 workInProgress.firstEffect = currentFallbackChild; 6854 currentFallbackChild.nextEffect = first; 6855 } else { 6856 workInProgress.firstEffect = workInProgress.lastEffect = currentFallbackChild; 6857 currentFallbackChild.nextEffect = null; 6858 } 6859 currentFallbackChild.effectTag = Deletion; 6860 } 6861 } 6862 6863 if (nextDidTimeout || prevDidTimeout) { 6864 // If the children are hidden, or if they were previous hidden, schedule 6865 // an effect to toggle their visibility. This is also used to attach a 6866 // retry listener to the promise. 6867 workInProgress.effectTag |= Update; 6868 } 6869 break; 6870 } 6871 case Fragment: 6872 break; 6873 case Mode: 6874 break; 6875 case Profiler: 6876 break; 6877 case HostPortal: 6878 popHostContainer(workInProgress); 6879 updateHostContainer(workInProgress); 6880 break; 6881 case ContextProvider: 6882 // Pop provider fiber 6883 popProvider(workInProgress); 6884 break; 6885 case ContextConsumer: 6886 break; 6887 case MemoComponent: 6888 break; 6889 case IncompleteClassComponent: 6890 { 6891 // Same as class component case. I put it down here so that the tags are 6892 // sequential to ensure this switch is compiled to a jump table. 6893 var _Component = workInProgress.type; 6894 if (isContextProvider(_Component)) { 6895 popContext(workInProgress); 6896 } 6897 break; 6898 } 6899 case DehydratedSuspenseComponent: 6900 { 6901 if (enableSuspenseServerRenderer) { 6902 if (current === null) { 6903 var _wasHydrated2 = popHydrationState(workInProgress); 6904 !_wasHydrated2 ? reactProdInvariant('318') : void 0; 6905 skipPastDehydratedSuspenseInstance(workInProgress); 6906 } else if ((workInProgress.effectTag & DidCapture) === NoEffect) { 6907 // This boundary did not suspend so it's now hydrated. 6908 // To handle any future suspense cases, we're going to now upgrade it 6909 // to a Suspense component. We detach it from the existing current fiber. 6910 current.alternate = null; 6911 workInProgress.alternate = null; 6912 workInProgress.tag = SuspenseComponent; 6913 workInProgress.memoizedState = null; 6914 workInProgress.stateNode = null; 6915 } 6916 } 6917 break; 6918 } 6919 default: 6920 reactProdInvariant('156'); 6921 } 6922 6923 return null; 6924 } 6925 6926 function shouldCaptureSuspense(workInProgress) { 6927 // In order to capture, the Suspense component must have a fallback prop. 6928 if (workInProgress.memoizedProps.fallback === undefined) { 6929 return false; 6930 } 6931 // If it was the primary children that just suspended, capture and render the 6932 // fallback. Otherwise, don't capture and bubble to the next boundary. 6933 var nextState = workInProgress.memoizedState; 6934 return nextState === null; 6935 } 6936 6937 // This module is forked in different environments. 6938 // By default, return `true` to log errors to the console. 6939 // Forks can return `false` if this isn't desirable. 6940 function showErrorDialog(capturedError) { 6941 return true; 6942 } 6943 6944 function logCapturedError(capturedError) { 6945 var logError = showErrorDialog(capturedError); 6946 6947 // Allow injected showErrorDialog() to prevent default console.error logging. 6948 // This enables renderers like ReactNative to better manage redbox behavior. 6949 if (logError === false) { 6950 return; 6951 } 6952 6953 var error = capturedError.error; 6954 { 6955 // In production, we print the error directly. 6956 // This will include the message, the JS stack, and anything the browser wants to show. 6957 // We pass the error object instead of custom message so that the browser displays the error natively. 6958 console.error(error); 6959 } 6960 } 6961 6962 var PossiblyWeakSet$1 = typeof WeakSet === 'function' ? WeakSet : Set; 6963 6964 function logError(boundary, errorInfo) { 6965 var source = errorInfo.source; 6966 var stack = errorInfo.stack; 6967 if (stack === null && source !== null) { 6968 stack = getStackByFiberInDevAndProd(source); 6969 } 6970 6971 var capturedError = { 6972 componentName: source !== null ? getComponentName(source.type) : null, 6973 componentStack: stack !== null ? stack : '', 6974 error: errorInfo.value, 6975 errorBoundary: null, 6976 errorBoundaryName: null, 6977 errorBoundaryFound: false, 6978 willRetry: false 6979 }; 6980 6981 if (boundary !== null && boundary.tag === ClassComponent) { 6982 capturedError.errorBoundary = boundary.stateNode; 6983 capturedError.errorBoundaryName = getComponentName(boundary.type); 6984 capturedError.errorBoundaryFound = true; 6985 capturedError.willRetry = true; 6986 } 6987 6988 try { 6989 logCapturedError(capturedError); 6990 } catch (e) { 6991 // This method must not throw, or React internal state will get messed up. 6992 // If console.error is overridden, or logCapturedError() shows a dialog that throws, 6993 // we want to report this error outside of the normal stack as a last resort. 6994 // https://github.com/facebook/react/issues/13188 6995 setTimeout(function () { 6996 throw e; 6997 }); 6998 } 6999 } 7000 7001 var callComponentWillUnmountWithTimer = function (current$$1, instance) { 7002 startPhaseTimer(current$$1, 'componentWillUnmount'); 7003 instance.props = current$$1.memoizedProps; 7004 instance.state = current$$1.memoizedState; 7005 instance.componentWillUnmount(); 7006 stopPhaseTimer(); 7007 }; 7008 7009 // Capture errors so they don't interrupt unmounting. 7010 function safelyCallComponentWillUnmount(current$$1, instance) { 7011 { 7012 try { 7013 callComponentWillUnmountWithTimer(current$$1, instance); 7014 } catch (unmountError) { 7015 captureCommitPhaseError(current$$1, unmountError); 7016 } 7017 } 7018 } 7019 7020 function safelyDetachRef(current$$1) { 7021 var ref = current$$1.ref; 7022 if (ref !== null) { 7023 if (typeof ref === 'function') { 7024 { 7025 try { 7026 ref(null); 7027 } catch (refError) { 7028 captureCommitPhaseError(current$$1, refError); 7029 } 7030 } 7031 } else { 7032 ref.current = null; 7033 } 7034 } 7035 } 7036 7037 function safelyCallDestroy(current$$1, destroy) { 7038 { 7039 try { 7040 destroy(); 7041 } catch (error) { 7042 captureCommitPhaseError(current$$1, error); 7043 } 7044 } 7045 } 7046 7047 function commitBeforeMutationLifeCycles(current$$1, finishedWork) { 7048 switch (finishedWork.tag) { 7049 case FunctionComponent: 7050 case ForwardRef: 7051 case SimpleMemoComponent: 7052 { 7053 commitHookEffectList(UnmountSnapshot, NoEffect$1, finishedWork); 7054 return; 7055 } 7056 case ClassComponent: 7057 { 7058 if (finishedWork.effectTag & Snapshot) { 7059 if (current$$1 !== null) { 7060 var prevProps = current$$1.memoizedProps; 7061 var prevState = current$$1.memoizedState; 7062 startPhaseTimer(finishedWork, 'getSnapshotBeforeUpdate'); 7063 var instance = finishedWork.stateNode; 7064 // We could update instance props and state here, 7065 // but instead we rely on them being set during last render. 7066 // TODO: revisit this when we implement resuming. 7067 var snapshot = instance.getSnapshotBeforeUpdate(finishedWork.elementType === finishedWork.type ? prevProps : resolveDefaultProps(finishedWork.type, prevProps), prevState); 7068 instance.__reactInternalSnapshotBeforeUpdate = snapshot; 7069 stopPhaseTimer(); 7070 } 7071 } 7072 return; 7073 } 7074 case HostRoot: 7075 case HostComponent: 7076 case HostText: 7077 case HostPortal: 7078 case IncompleteClassComponent: 7079 // Nothing to do for these component types 7080 return; 7081 default: 7082 { 7083 reactProdInvariant('163'); 7084 } 7085 } 7086 } 7087 7088 function commitHookEffectList(unmountTag, mountTag, finishedWork) { 7089 var updateQueue = finishedWork.updateQueue; 7090 var lastEffect = updateQueue !== null ? updateQueue.lastEffect : null; 7091 if (lastEffect !== null) { 7092 var firstEffect = lastEffect.next; 7093 var effect = firstEffect; 7094 do { 7095 if ((effect.tag & unmountTag) !== NoEffect$1) { 7096 // Unmount 7097 var destroy = effect.destroy; 7098 effect.destroy = undefined; 7099 if (destroy !== undefined) { 7100 destroy(); 7101 } 7102 } 7103 if ((effect.tag & mountTag) !== NoEffect$1) { 7104 // Mount 7105 var create = effect.create; 7106 effect.destroy = create(); 7107 7108 7109 } 7110 effect = effect.next; 7111 } while (effect !== firstEffect); 7112 } 7113 } 7114 7115 function commitPassiveHookEffects(finishedWork) { 7116 commitHookEffectList(UnmountPassive, NoEffect$1, finishedWork); 7117 commitHookEffectList(NoEffect$1, MountPassive, finishedWork); 7118 } 7119 7120 function commitLifeCycles(finishedRoot, current$$1, finishedWork, committedExpirationTime) { 7121 switch (finishedWork.tag) { 7122 case FunctionComponent: 7123 case ForwardRef: 7124 case SimpleMemoComponent: 7125 { 7126 commitHookEffectList(UnmountLayout, MountLayout, finishedWork); 7127 break; 7128 } 7129 case ClassComponent: 7130 { 7131 var instance = finishedWork.stateNode; 7132 if (finishedWork.effectTag & Update) { 7133 if (current$$1 === null) { 7134 startPhaseTimer(finishedWork, 'componentDidMount'); 7135 // We could update instance props and state here, 7136 // but instead we rely on them being set during last render. 7137 // TODO: revisit this when we implement resuming. 7138 instance.componentDidMount(); 7139 stopPhaseTimer(); 7140 } else { 7141 var prevProps = finishedWork.elementType === finishedWork.type ? current$$1.memoizedProps : resolveDefaultProps(finishedWork.type, current$$1.memoizedProps); 7142 var prevState = current$$1.memoizedState; 7143 startPhaseTimer(finishedWork, 'componentDidUpdate'); 7144 // We could update instance props and state here, 7145 // but instead we rely on them being set during last render. 7146 // TODO: revisit this when we implement resuming. 7147 instance.componentDidUpdate(prevProps, prevState, instance.__reactInternalSnapshotBeforeUpdate); 7148 stopPhaseTimer(); 7149 } 7150 } 7151 var updateQueue = finishedWork.updateQueue; 7152 if (updateQueue !== null) { 7153 commitUpdateQueue(finishedWork, updateQueue, instance, committedExpirationTime); 7154 } 7155 return; 7156 } 7157 case HostRoot: 7158 { 7159 var _updateQueue = finishedWork.updateQueue; 7160 if (_updateQueue !== null) { 7161 var _instance = null; 7162 if (finishedWork.child !== null) { 7163 switch (finishedWork.child.tag) { 7164 case HostComponent: 7165 _instance = getPublicInstance(finishedWork.child.stateNode); 7166 break; 7167 case ClassComponent: 7168 _instance = finishedWork.child.stateNode; 7169 break; 7170 } 7171 } 7172 commitUpdateQueue(finishedWork, _updateQueue, _instance, committedExpirationTime); 7173 } 7174 return; 7175 } 7176 case HostComponent: 7177 { 7178 var _instance2 = finishedWork.stateNode; 7179 7180 // Renderers may schedule work to be done after host components are mounted 7181 // (eg DOM renderer may schedule auto-focus for inputs and form controls). 7182 // These effects should only be committed when components are first mounted, 7183 // aka when there is no current/alternate. 7184 if (current$$1 === null && finishedWork.effectTag & Update) { 7185 var type = finishedWork.type; 7186 var props = finishedWork.memoizedProps; 7187 7188 } 7189 7190 return; 7191 } 7192 case HostText: 7193 { 7194 // We have no life-cycles associated with text. 7195 return; 7196 } 7197 case HostPortal: 7198 { 7199 // We have no life-cycles associated with portals. 7200 return; 7201 } 7202 case Profiler: 7203 { 7204 if (enableProfilerTimer) { 7205 var onRender = finishedWork.memoizedProps.onRender; 7206 7207 if (enableSchedulerTracing) { 7208 onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime(), finishedRoot.memoizedInteractions); 7209 } else { 7210 onRender(finishedWork.memoizedProps.id, current$$1 === null ? 'mount' : 'update', finishedWork.actualDuration, finishedWork.treeBaseDuration, finishedWork.actualStartTime, getCommitTime()); 7211 } 7212 } 7213 return; 7214 } 7215 case SuspenseComponent: 7216 break; 7217 case IncompleteClassComponent: 7218 break; 7219 default: 7220 { 7221 reactProdInvariant('163'); 7222 } 7223 } 7224 } 7225 7226 function hideOrUnhideAllChildren(finishedWork, isHidden) { 7227 if (supportsMutation) { 7228 // We only have the top Fiber that was inserted but we need to recurse down its 7229 var node = finishedWork; 7230 while (true) { 7231 if (node.tag === HostComponent) { 7232 var instance = node.stateNode; 7233 if (isHidden) { 7234 hideInstance(instance); 7235 } else { 7236 unhideInstance(node.stateNode, node.memoizedProps); 7237 } 7238 } else if (node.tag === HostText) { 7239 var _instance3 = node.stateNode; 7240 if (isHidden) { 7241 hideTextInstance(_instance3); 7242 } else { 7243 unhideTextInstance(_instance3, node.memoizedProps); 7244 } 7245 } else if (node.tag === SuspenseComponent && node.memoizedState !== null) { 7246 // Found a nested Suspense component that timed out. Skip over the 7247 var fallbackChildFragment = node.child.sibling; 7248 fallbackChildFragment.return = node; 7249 node = fallbackChildFragment; 7250 continue; 7251 } else if (node.child !== null) { 7252 node.child.return = node; 7253 node = node.child; 7254 continue; 7255 } 7256 if (node === finishedWork) { 7257 return; 7258 } 7259 while (node.sibling === null) { 7260 if (node.return === null || node.return === finishedWork) { 7261 return; 7262 } 7263 node = node.return; 7264 } 7265 node.sibling.return = node.return; 7266 node = node.sibling; 7267 } 7268 } 7269 } 7270 7271 function commitAttachRef(finishedWork) { 7272 var ref = finishedWork.ref; 7273 if (ref !== null) { 7274 var instance = finishedWork.stateNode; 7275 var instanceToUse = void 0; 7276 switch (finishedWork.tag) { 7277 case HostComponent: 7278 instanceToUse = getPublicInstance(instance); 7279 break; 7280 default: 7281 instanceToUse = instance; 7282 } 7283 if (typeof ref === 'function') { 7284 ref(instanceToUse); 7285 } else { 7286 ref.current = instanceToUse; 7287 } 7288 } 7289 } 7290 7291 function commitDetachRef(current$$1) { 7292 var currentRef = current$$1.ref; 7293 if (currentRef !== null) { 7294 if (typeof currentRef === 'function') { 7295 currentRef(null); 7296 } else { 7297 currentRef.current = null; 7298 } 7299 } 7300 } 7301 7302 // User-originating errors (lifecycles and refs) should not interrupt 7303 // deletion, so don't let them throw. Host-originating errors should 7304 // interrupt deletion, so it's okay 7305 function commitUnmount(current$$1) { 7306 onCommitUnmount(current$$1); 7307 7308 switch (current$$1.tag) { 7309 case FunctionComponent: 7310 case ForwardRef: 7311 case MemoComponent: 7312 case SimpleMemoComponent: 7313 { 7314 var updateQueue = current$$1.updateQueue; 7315 if (updateQueue !== null) { 7316 var lastEffect = updateQueue.lastEffect; 7317 if (lastEffect !== null) { 7318 var firstEffect = lastEffect.next; 7319 var effect = firstEffect; 7320 do { 7321 var destroy = effect.destroy; 7322 if (destroy !== undefined) { 7323 safelyCallDestroy(current$$1, destroy); 7324 } 7325 effect = effect.next; 7326 } while (effect !== firstEffect); 7327 } 7328 } 7329 break; 7330 } 7331 case ClassComponent: 7332 { 7333 safelyDetachRef(current$$1); 7334 var instance = current$$1.stateNode; 7335 if (typeof instance.componentWillUnmount === 'function') { 7336 safelyCallComponentWillUnmount(current$$1, instance); 7337 } 7338 return; 7339 } 7340 case HostComponent: 7341 { 7342 safelyDetachRef(current$$1); 7343 return; 7344 } 7345 case HostPortal: 7346 { 7347 // TODO: this is recursive. 7348 // We are also not using this parent because 7349 // the portal will get pushed immediately. 7350 if (supportsMutation) { 7351 unmountHostComponents(current$$1); 7352 } else if (supportsPersistence) { 7353 emptyPortalContainer(current$$1); 7354 } 7355 return; 7356 } 7357 } 7358 } 7359 7360 function commitNestedUnmounts(root) { 7361 // While we're inside a removed host node we don't want to call 7362 // removeChild on the inner nodes because they're removed by the top 7363 // call anyway. We also want to call componentWillUnmount on all 7364 // composites before this host node is removed from the tree. Therefore 7365 var node = root; 7366 while (true) { 7367 commitUnmount(node); 7368 // Visit children because they may contain more composite or host nodes. 7369 // Skip portals because commitUnmount() currently visits them recursively. 7370 if (node.child !== null && ( 7371 // If we use mutation we drill down into portals using commitUnmount above. 7372 // If we don't use mutation we drill down into portals here instead. 7373 !supportsMutation || node.tag !== HostPortal)) { 7374 node.child.return = node; 7375 node = node.child; 7376 continue; 7377 } 7378 if (node === root) { 7379 return; 7380 } 7381 while (node.sibling === null) { 7382 if (node.return === null || node.return === root) { 7383 return; 7384 } 7385 node = node.return; 7386 } 7387 node.sibling.return = node.return; 7388 node = node.sibling; 7389 } 7390 } 7391 7392 function detachFiber(current$$1) { 7393 // Cut off the return pointers to disconnect it from the tree. Ideally, we 7394 // should clear the child pointer of the parent alternate to let this 7395 // get GC:ed but we don't know which for sure which parent is the current 7396 // one so we'll settle for GC:ing the subtree of this child. This child 7397 // itself will be GC:ed when the parent updates the next time. 7398 current$$1.return = null; 7399 current$$1.child = null; 7400 current$$1.memoizedState = null; 7401 current$$1.updateQueue = null; 7402 var alternate = current$$1.alternate; 7403 if (alternate !== null) { 7404 alternate.return = null; 7405 alternate.child = null; 7406 alternate.memoizedState = null; 7407 alternate.updateQueue = null; 7408 } 7409 } 7410 7411 function emptyPortalContainer(current$$1) { 7412 if (!supportsPersistence) { 7413 return; 7414 } 7415 7416 var portal = current$$1.stateNode; 7417 var containerInfo = portal.containerInfo; 7418 7419 var emptyChildSet = createContainerChildSet(containerInfo); 7420 replaceContainerChildren(containerInfo, emptyChildSet); 7421 } 7422 7423 function commitContainer(finishedWork) { 7424 if (!supportsPersistence) { 7425 return; 7426 } 7427 7428 switch (finishedWork.tag) { 7429 case ClassComponent: 7430 { 7431 return; 7432 } 7433 case HostComponent: 7434 { 7435 return; 7436 } 7437 case HostText: 7438 { 7439 return; 7440 } 7441 case HostRoot: 7442 case HostPortal: 7443 { 7444 var portalOrRoot = finishedWork.stateNode; 7445 var containerInfo = portalOrRoot.containerInfo, 7446 _pendingChildren = portalOrRoot.pendingChildren; 7447 7448 replaceContainerChildren(containerInfo, _pendingChildren); 7449 return; 7450 } 7451 default: 7452 { 7453 reactProdInvariant('163'); 7454 } 7455 } 7456 } 7457 7458 function getHostParentFiber(fiber) { 7459 var parent = fiber.return; 7460 while (parent !== null) { 7461 if (isHostParent(parent)) { 7462 return parent; 7463 } 7464 parent = parent.return; 7465 } 7466 reactProdInvariant('160'); 7467 } 7468 7469 function isHostParent(fiber) { 7470 return fiber.tag === HostComponent || fiber.tag === HostRoot || fiber.tag === HostPortal; 7471 } 7472 7473 function getHostSibling(fiber) { 7474 // We're going to search forward into the tree until we find a sibling host 7475 // node. Unfortunately, if multiple insertions are done in a row we have to 7476 // search past them. This leads to exponential search for the next sibling. 7477 var node = fiber; 7478 siblings: while (true) { 7479 // If we didn't find anything, let's try the next sibling. 7480 while (node.sibling === null) { 7481 if (node.return === null || isHostParent(node.return)) { 7482 // If we pop out of the root or hit the parent the fiber we are the 7483 // last sibling. 7484 return null; 7485 } 7486 node = node.return; 7487 } 7488 node.sibling.return = node.return; 7489 node = node.sibling; 7490 while (node.tag !== HostComponent && node.tag !== HostText && node.tag !== DehydratedSuspenseComponent) { 7491 // If it is not host node and, we might have a host node inside it. 7492 // Try to search down until we find one. 7493 if (node.effectTag & Placement) { 7494 // If we don't have a child, try the siblings instead. 7495 continue siblings; 7496 } 7497 // If we don't have a child, try the siblings instead. 7498 // We also skip portals because they are not part of this host tree. 7499 if (node.child === null || node.tag === HostPortal) { 7500 continue siblings; 7501 } else { 7502 node.child.return = node; 7503 node = node.child; 7504 } 7505 } 7506 // Check if this host node is stable or about to be placed. 7507 if (!(node.effectTag & Placement)) { 7508 // Found it! 7509 return node.stateNode; 7510 } 7511 } 7512 } 7513 7514 function commitPlacement(finishedWork) { 7515 if (!supportsMutation) { 7516 return; 7517 } 7518 7519 // Recursively insert all host nodes into the parent. 7520 var parentFiber = getHostParentFiber(finishedWork); 7521 7522 // Note: these two variables *must* always be updated together. 7523 var parent = void 0; 7524 var isContainer = void 0; 7525 7526 switch (parentFiber.tag) { 7527 case HostComponent: 7528 parent = parentFiber.stateNode; 7529 isContainer = false; 7530 break; 7531 case HostRoot: 7532 parent = parentFiber.stateNode.containerInfo; 7533 isContainer = true; 7534 break; 7535 case HostPortal: 7536 parent = parentFiber.stateNode.containerInfo; 7537 isContainer = true; 7538 break; 7539 default: 7540 reactProdInvariant('161'); 7541 } 7542 if (parentFiber.effectTag & ContentReset) { 7543 // Reset the text content of the parent before doing any insertions 7544 parentFiber.effectTag &= ~ContentReset; 7545 } 7546 7547 var before = getHostSibling(finishedWork); 7548 // We only have the top Fiber that was inserted but we need to recurse down its 7549 // children to find all the terminal nodes. 7550 var node = finishedWork; 7551 while (true) { 7552 if (node.tag === HostComponent || node.tag === HostText) { 7553 if (before) { 7554 if (isContainer) { 7555 insertInContainerBefore(parent, node.stateNode, before); 7556 } else { 7557 insertBefore(parent, node.stateNode, before); 7558 } 7559 } else { 7560 if (isContainer) { 7561 appendChildToContainer(parent, node.stateNode); 7562 } else { 7563 appendChild(parent, node.stateNode); 7564 } 7565 } 7566 } else if (node.tag === HostPortal) { 7567 // If the insertion itself is a portal, then we don't want to traverse 7568 // down its children. Instead, we'll get insertions from each child in 7569 // the portal directly. 7570 } else if (node.child !== null) { 7571 node.child.return = node; 7572 node = node.child; 7573 continue; 7574 } 7575 if (node === finishedWork) { 7576 return; 7577 } 7578 while (node.sibling === null) { 7579 if (node.return === null || node.return === finishedWork) { 7580 return; 7581 } 7582 node = node.return; 7583 } 7584 node.sibling.return = node.return; 7585 node = node.sibling; 7586 } 7587 } 7588 7589 function unmountHostComponents(current$$1) { 7590 // We only have the top Fiber that was deleted but we need to recurse down its 7591 var node = current$$1; 7592 7593 // Each iteration, currentParent is populated with node's host parent if not 7594 // currentParentIsValid. 7595 var currentParentIsValid = false; 7596 7597 // Note: these two variables *must* always be updated together. 7598 var currentParent = void 0; 7599 var currentParentIsContainer = void 0; 7600 7601 while (true) { 7602 if (!currentParentIsValid) { 7603 var parent = node.return; 7604 findParent: while (true) { 7605 !(parent !== null) ? reactProdInvariant('160') : void 0; 7606 switch (parent.tag) { 7607 case HostComponent: 7608 currentParent = parent.stateNode; 7609 currentParentIsContainer = false; 7610 break findParent; 7611 case HostRoot: 7612 currentParent = parent.stateNode.containerInfo; 7613 currentParentIsContainer = true; 7614 break findParent; 7615 case HostPortal: 7616 currentParent = parent.stateNode.containerInfo; 7617 currentParentIsContainer = true; 7618 break findParent; 7619 } 7620 parent = parent.return; 7621 } 7622 currentParentIsValid = true; 7623 } 7624 7625 if (node.tag === HostComponent || node.tag === HostText) { 7626 commitNestedUnmounts(node); 7627 // After all the children have unmounted, it is now safe to remove the 7628 // node from the tree. 7629 if (currentParentIsContainer) { 7630 removeChildFromContainer(currentParent, node.stateNode); 7631 } else { 7632 removeChild(currentParent, node.stateNode); 7633 } 7634 // Don't visit children because we already visited them. 7635 } else if (enableSuspenseServerRenderer && node.tag === DehydratedSuspenseComponent) { 7636 // Delete the dehydrated suspense boundary and all of its content. 7637 if (currentParentIsContainer) { 7638 clearSuspenseBoundaryFromContainer(currentParent, node.stateNode); 7639 } else { 7640 clearSuspenseBoundary(currentParent, node.stateNode); 7641 } 7642 } else if (node.tag === HostPortal) { 7643 if (node.child !== null) { 7644 // When we go into a portal, it becomes the parent to remove from. 7645 // We will reassign it back when we pop the portal on the way up. 7646 currentParent = node.stateNode.containerInfo; 7647 currentParentIsContainer = true; 7648 // Visit children because portals might contain host components. 7649 node.child.return = node; 7650 node = node.child; 7651 continue; 7652 } 7653 } else { 7654 commitUnmount(node); 7655 // Visit children because we may find more host components below. 7656 if (node.child !== null) { 7657 node.child.return = node; 7658 node = node.child; 7659 continue; 7660 } 7661 } 7662 if (node === current$$1) { 7663 return; 7664 } 7665 while (node.sibling === null) { 7666 if (node.return === null || node.return === current$$1) { 7667 return; 7668 } 7669 node = node.return; 7670 if (node.tag === HostPortal) { 7671 // When we go out of the portal, we need to restore the parent. 7672 // Since we don't keep a stack of them, we will search for it. 7673 currentParentIsValid = false; 7674 } 7675 } 7676 node.sibling.return = node.return; 7677 node = node.sibling; 7678 } 7679 } 7680 7681 function commitDeletion(current$$1) { 7682 if (supportsMutation) { 7683 // Recursively delete all host nodes from the parent. 7684 // Detach refs and call componentWillUnmount() on the whole subtree. 7685 unmountHostComponents(current$$1); 7686 } else { 7687 // Detach refs and call componentWillUnmount() on the whole subtree. 7688 commitNestedUnmounts(current$$1); 7689 } 7690 detachFiber(current$$1); 7691 } 7692 7693 function commitWork(current$$1, finishedWork) { 7694 if (!supportsMutation) { 7695 switch (finishedWork.tag) { 7696 case FunctionComponent: 7697 case ForwardRef: 7698 case MemoComponent: 7699 case SimpleMemoComponent: 7700 { 7701 // Note: We currently never use MountMutation, but useLayout uses 7702 // UnmountMutation. 7703 commitHookEffectList(UnmountMutation, MountMutation, finishedWork); 7704 return; 7705 } 7706 } 7707 7708 commitContainer(finishedWork); 7709 return; 7710 } 7711 7712 switch (finishedWork.tag) { 7713 case FunctionComponent: 7714 case ForwardRef: 7715 case MemoComponent: 7716 case SimpleMemoComponent: 7717 { 7718 // Note: We currently never use MountMutation, but useLayout uses 7719 // UnmountMutation. 7720 commitHookEffectList(UnmountMutation, MountMutation, finishedWork); 7721 return; 7722 } 7723 case ClassComponent: 7724 { 7725 return; 7726 } 7727 case HostComponent: 7728 { 7729 var instance = finishedWork.stateNode; 7730 if (instance != null) { 7731 // Commit the work prepared earlier. 7732 var newProps = finishedWork.memoizedProps; 7733 // For hydration we reuse the update path but we treat the oldProps 7734 // as the newProps. The updatePayload will contain the real change in 7735 // this case. 7736 var oldProps = current$$1 !== null ? current$$1.memoizedProps : newProps; 7737 var type = finishedWork.type; 7738 // TODO: Type the updateQueue to be specific to host components. 7739 var updatePayload = finishedWork.updateQueue; 7740 finishedWork.updateQueue = null; 7741 if (updatePayload !== null) { 7742 commitUpdate(instance, updatePayload, type, oldProps, newProps, finishedWork); 7743 } 7744 } 7745 return; 7746 } 7747 case HostText: 7748 { 7749 !(finishedWork.stateNode !== null) ? reactProdInvariant('162') : void 0; 7750 var textInstance = finishedWork.stateNode; 7751 var newText = finishedWork.memoizedProps; 7752 // For hydration we reuse the update path but we treat the oldProps 7753 // as the newProps. The updatePayload will contain the real change in 7754 // this case. 7755 var oldText = current$$1 !== null ? current$$1.memoizedProps : newText; 7756 commitTextUpdate(textInstance, oldText, newText); 7757 return; 7758 } 7759 case HostRoot: 7760 { 7761 return; 7762 } 7763 case Profiler: 7764 { 7765 return; 7766 } 7767 case SuspenseComponent: 7768 { 7769 var newState = finishedWork.memoizedState; 7770 7771 var newDidTimeout = void 0; 7772 var primaryChildParent = finishedWork; 7773 if (newState === null) { 7774 newDidTimeout = false; 7775 } else { 7776 newDidTimeout = true; 7777 primaryChildParent = finishedWork.child; 7778 if (newState.timedOutAt === NoWork) { 7779 // If the children had not already timed out, record the time. 7780 // This is used to compute the elapsed time during subsequent 7781 // attempts to render the children. 7782 newState.timedOutAt = requestCurrentTime(); 7783 } 7784 } 7785 7786 if (primaryChildParent !== null) { 7787 hideOrUnhideAllChildren(primaryChildParent, newDidTimeout); 7788 } 7789 7790 // If this boundary just timed out, then it will have a set of thenables. 7791 // For each thenable, attach a listener so that when it resolves, React 7792 // attempts to re-render the boundary in the primary (pre-timeout) state. 7793 var thenables = finishedWork.updateQueue; 7794 if (thenables !== null) { 7795 finishedWork.updateQueue = null; 7796 var retryCache = finishedWork.stateNode; 7797 if (retryCache === null) { 7798 retryCache = finishedWork.stateNode = new PossiblyWeakSet$1(); 7799 } 7800 thenables.forEach(function (thenable) { 7801 // Memoize using the boundary fiber to prevent redundant listeners. 7802 var retry = retryTimedOutBoundary.bind(null, finishedWork, thenable); 7803 if (enableSchedulerTracing) { 7804 retry = unstable_wrap(retry); 7805 } 7806 if (!retryCache.has(thenable)) { 7807 retryCache.add(thenable); 7808 thenable.then(retry, retry); 7809 } 7810 }); 7811 } 7812 7813 return; 7814 } 7815 case IncompleteClassComponent: 7816 { 7817 return; 7818 } 7819 default: 7820 { 7821 reactProdInvariant('163'); 7822 } 7823 } 7824 } 7825 7826 function commitResetTextContent(current$$1) { 7827 if (!supportsMutation) { 7828 return; 7829 } 7830 resetTextContent(current$$1.stateNode); 7831 } 7832 7833 var PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set; 7834 var PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map; 7835 7836 function createRootErrorUpdate(fiber, errorInfo, expirationTime) { 7837 var update = createUpdate(expirationTime); 7838 // Unmount the root by rendering null. 7839 update.tag = CaptureUpdate; 7840 // Caution: React DevTools currently depends on this property 7841 // being called "element". 7842 update.payload = { element: null }; 7843 var error = errorInfo.value; 7844 update.callback = function () { 7845 onUncaughtError(error); 7846 logError(fiber, errorInfo); 7847 }; 7848 return update; 7849 } 7850 7851 function createClassErrorUpdate(fiber, errorInfo, expirationTime) { 7852 var update = createUpdate(expirationTime); 7853 update.tag = CaptureUpdate; 7854 var getDerivedStateFromError = fiber.type.getDerivedStateFromError; 7855 if (typeof getDerivedStateFromError === 'function') { 7856 var error = errorInfo.value; 7857 update.payload = function () { 7858 return getDerivedStateFromError(error); 7859 }; 7860 } 7861 7862 var inst = fiber.stateNode; 7863 if (inst !== null && typeof inst.componentDidCatch === 'function') { 7864 update.callback = function callback() { 7865 if (typeof getDerivedStateFromError !== 'function') { 7866 // To preserve the preexisting retry behavior of error boundaries, 7867 // we keep track of which ones already failed during this batch. 7868 // This gets reset before we yield back to the browser. 7869 // TODO: Warn in strict mode if getDerivedStateFromError is 7870 // not defined. 7871 markLegacyErrorBoundaryAsFailed(this); 7872 } 7873 var error = errorInfo.value; 7874 var stack = errorInfo.stack; 7875 logError(fiber, errorInfo); 7876 this.componentDidCatch(error, { 7877 componentStack: stack !== null ? stack : '' 7878 }); 7879 7880 }; 7881 } 7882 return update; 7883 } 7884 7885 function attachPingListener(root, renderExpirationTime, thenable) { 7886 // Attach a listener to the promise to "ping" the root and retry. But 7887 // only if one does not already exist for the current render expiration 7888 // time (which acts like a "thread ID" here). 7889 var pingCache = root.pingCache; 7890 var threadIDs = void 0; 7891 if (pingCache === null) { 7892 pingCache = root.pingCache = new PossiblyWeakMap(); 7893 threadIDs = new Set(); 7894 pingCache.set(thenable, threadIDs); 7895 } else { 7896 threadIDs = pingCache.get(thenable); 7897 if (threadIDs === undefined) { 7898 threadIDs = new Set(); 7899 pingCache.set(thenable, threadIDs); 7900 } 7901 } 7902 if (!threadIDs.has(renderExpirationTime)) { 7903 // Memoize using the thread ID to prevent redundant listeners. 7904 threadIDs.add(renderExpirationTime); 7905 var ping = pingSuspendedRoot.bind(null, root, thenable, renderExpirationTime); 7906 if (enableSchedulerTracing) { 7907 ping = unstable_wrap(ping); 7908 } 7909 thenable.then(ping, ping); 7910 } 7911 } 7912 7913 function throwException(root, returnFiber, sourceFiber, value, renderExpirationTime) { 7914 // The source fiber did not complete. 7915 sourceFiber.effectTag |= Incomplete; 7916 // Its effect list is no longer valid. 7917 sourceFiber.firstEffect = sourceFiber.lastEffect = null; 7918 7919 if (value !== null && typeof value === 'object' && typeof value.then === 'function') { 7920 // This is a thenable. 7921 var thenable = value; 7922 7923 // Find the earliest timeout threshold of all the placeholders in the 7924 // ancestor path. We could avoid this traversal by storing the thresholds on 7925 // the stack, but we choose not to because we only hit this path if we're 7926 // IO-bound (i.e. if something suspends). Whereas the stack is used even in 7927 // the non-IO- bound case. 7928 var _workInProgress = returnFiber; 7929 var earliestTimeoutMs = -1; 7930 var startTimeMs = -1; 7931 do { 7932 if (_workInProgress.tag === SuspenseComponent) { 7933 var current$$1 = _workInProgress.alternate; 7934 if (current$$1 !== null) { 7935 var currentState = current$$1.memoizedState; 7936 if (currentState !== null) { 7937 // Reached a boundary that already timed out. Do not search 7938 // any further. 7939 var timedOutAt = currentState.timedOutAt; 7940 startTimeMs = expirationTimeToMs(timedOutAt); 7941 // Do not search any further. 7942 break; 7943 } 7944 } 7945 var timeoutPropMs = _workInProgress.pendingProps.maxDuration; 7946 if (typeof timeoutPropMs === 'number') { 7947 if (timeoutPropMs <= 0) { 7948 earliestTimeoutMs = 0; 7949 } else if (earliestTimeoutMs === -1 || timeoutPropMs < earliestTimeoutMs) { 7950 earliestTimeoutMs = timeoutPropMs; 7951 } 7952 } 7953 } 7954 // If there is a DehydratedSuspenseComponent we don't have to do anything because 7955 // if something suspends inside it, we will simply leave that as dehydrated. It 7956 // will never timeout. 7957 _workInProgress = _workInProgress.return; 7958 } while (_workInProgress !== null); 7959 7960 // Schedule the nearest Suspense to re-render the timed out view. 7961 _workInProgress = returnFiber; 7962 do { 7963 if (_workInProgress.tag === SuspenseComponent && shouldCaptureSuspense(_workInProgress)) { 7964 // Found the nearest boundary. 7965 7966 // Stash the promise on the boundary fiber. If the boundary times out, we'll 7967 var thenables = _workInProgress.updateQueue; 7968 if (thenables === null) { 7969 var updateQueue = new Set(); 7970 updateQueue.add(thenable); 7971 _workInProgress.updateQueue = updateQueue; 7972 } else { 7973 thenables.add(thenable); 7974 } 7975 7976 // If the boundary is outside of concurrent mode, we should *not* 7977 // suspend the commit. Pretend as if the suspended component rendered 7978 // null and keep rendering. In the commit phase, we'll schedule a 7979 // subsequent synchronous update to re-render the Suspense. 7980 // 7981 // Note: It doesn't matter whether the component that suspended was 7982 // inside a concurrent mode tree. If the Suspense is outside of it, we 7983 // should *not* suspend the commit. 7984 if ((_workInProgress.mode & ConcurrentMode) === NoEffect) { 7985 _workInProgress.effectTag |= DidCapture; 7986 7987 // We're going to commit this fiber even though it didn't complete. 7988 // But we shouldn't call any lifecycle methods or callbacks. Remove 7989 // all lifecycle effect tags. 7990 sourceFiber.effectTag &= ~(LifecycleEffectMask | Incomplete); 7991 7992 if (sourceFiber.tag === ClassComponent) { 7993 var currentSourceFiber = sourceFiber.alternate; 7994 if (currentSourceFiber === null) { 7995 // This is a new mount. Change the tag so it's not mistaken for a 7996 // completed class component. For example, we should not call 7997 // componentWillUnmount if it is deleted. 7998 sourceFiber.tag = IncompleteClassComponent; 7999 } else { 8000 // When we try rendering again, we should not reuse the current fiber, 8001 // since it's known to be in an inconsistent state. Use a force updte to 8002 // prevent a bail out. 8003 var update = createUpdate(Sync); 8004 update.tag = ForceUpdate; 8005 enqueueUpdate(sourceFiber, update); 8006 } 8007 } 8008 8009 // The source fiber did not complete. Mark it with Sync priority to 8010 // indicate that it still has pending work. 8011 sourceFiber.expirationTime = Sync; 8012 8013 // Exit without suspending. 8014 return; 8015 } 8016 8017 // Confirmed that the boundary is in a concurrent mode tree. Continue 8018 // with the normal suspend path. 8019 8020 attachPingListener(root, renderExpirationTime, thenable); 8021 8022 var absoluteTimeoutMs = void 0; 8023 if (earliestTimeoutMs === -1) { 8024 // If no explicit threshold is given, default to an arbitrarily large 8025 // value. The actual size doesn't matter because the threshold for the 8026 // whole tree will be clamped to the expiration time. 8027 absoluteTimeoutMs = maxSigned31BitInt; 8028 } else { 8029 if (startTimeMs === -1) { 8030 // This suspend happened outside of any already timed-out 8031 // placeholders. We don't know exactly when the update was 8032 // scheduled, but we can infer an approximate start time from the 8033 // expiration time. First, find the earliest uncommitted expiration 8034 // time in the tree, including work that is suspended. Then subtract 8035 // the offset used to compute an async update's expiration time. 8036 // This will cause high priority (interactive) work to expire 8037 // earlier than necessary, but we can account for this by adjusting 8038 // for the Just Noticeable Difference. 8039 var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, renderExpirationTime); 8040 var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); 8041 startTimeMs = earliestExpirationTimeMs - LOW_PRIORITY_EXPIRATION; 8042 } 8043 absoluteTimeoutMs = startTimeMs + earliestTimeoutMs; 8044 } 8045 8046 // Mark the earliest timeout in the suspended fiber's ancestor path. 8047 // After completing the root, we'll take the largest of all the 8048 // suspended fiber's timeouts and use it to compute a timeout for the 8049 // whole tree. 8050 renderDidSuspend(root, absoluteTimeoutMs, renderExpirationTime); 8051 8052 _workInProgress.effectTag |= ShouldCapture; 8053 _workInProgress.expirationTime = renderExpirationTime; 8054 return; 8055 } else if (enableSuspenseServerRenderer && _workInProgress.tag === DehydratedSuspenseComponent) { 8056 attachPingListener(root, renderExpirationTime, thenable); 8057 8058 // Since we already have a current fiber, we can eagerly add a retry listener. 8059 var retryCache = _workInProgress.memoizedState; 8060 if (retryCache === null) { 8061 retryCache = _workInProgress.memoizedState = new PossiblyWeakSet(); 8062 var _current = _workInProgress.alternate; 8063 !_current ? reactProdInvariant('319') : void 0; 8064 _current.memoizedState = retryCache; 8065 } 8066 // Memoize using the boundary fiber to prevent redundant listeners. 8067 if (!retryCache.has(thenable)) { 8068 retryCache.add(thenable); 8069 var retry = retryTimedOutBoundary.bind(null, _workInProgress, thenable); 8070 if (enableSchedulerTracing) { 8071 retry = unstable_wrap(retry); 8072 } 8073 thenable.then(retry, retry); 8074 } 8075 _workInProgress.effectTag |= ShouldCapture; 8076 _workInProgress.expirationTime = renderExpirationTime; 8077 return; 8078 } 8079 // This boundary already captured during this render. Continue to the next 8080 // boundary. 8081 _workInProgress = _workInProgress.return; 8082 } while (_workInProgress !== null); 8083 // No boundary was found. Fallthrough to error mode. 8084 // TODO: Use invariant so the message is stripped in prod? 8085 value = new Error((getComponentName(sourceFiber.type) || 'A React component') + ' suspended while rendering, but no fallback UI was specified.\n' + '\n' + 'Add a <Suspense fallback=...> component higher in the tree to ' + 'provide a loading indicator or placeholder to display.' + getStackByFiberInDevAndProd(sourceFiber)); 8086 } 8087 8088 // We didn't find a boundary that could handle this type of exception. Start 8089 // over and traverse parent path again, this time treating the exception 8090 // as an error. 8091 renderDidError(); 8092 value = createCapturedValue(value, sourceFiber); 8093 var workInProgress = returnFiber; 8094 do { 8095 switch (workInProgress.tag) { 8096 case HostRoot: 8097 { 8098 var _errorInfo = value; 8099 workInProgress.effectTag |= ShouldCapture; 8100 workInProgress.expirationTime = renderExpirationTime; 8101 var _update = createRootErrorUpdate(workInProgress, _errorInfo, renderExpirationTime); 8102 enqueueCapturedUpdate(workInProgress, _update); 8103 return; 8104 } 8105 case ClassComponent: 8106 // Capture and retry 8107 var errorInfo = value; 8108 var ctor = workInProgress.type; 8109 var instance = workInProgress.stateNode; 8110 if ((workInProgress.effectTag & DidCapture) === NoEffect && (typeof ctor.getDerivedStateFromError === 'function' || instance !== null && typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance))) { 8111 workInProgress.effectTag |= ShouldCapture; 8112 workInProgress.expirationTime = renderExpirationTime; 8113 // Schedule the error boundary to re-render using updated state 8114 var _update2 = createClassErrorUpdate(workInProgress, errorInfo, renderExpirationTime); 8115 enqueueCapturedUpdate(workInProgress, _update2); 8116 return; 8117 } 8118 break; 8119 default: 8120 break; 8121 } 8122 workInProgress = workInProgress.return; 8123 } while (workInProgress !== null); 8124 } 8125 8126 function unwindWork(workInProgress, renderExpirationTime) { 8127 switch (workInProgress.tag) { 8128 case ClassComponent: 8129 { 8130 var Component = workInProgress.type; 8131 if (isContextProvider(Component)) { 8132 popContext(workInProgress); 8133 } 8134 var effectTag = workInProgress.effectTag; 8135 if (effectTag & ShouldCapture) { 8136 workInProgress.effectTag = effectTag & ~ShouldCapture | DidCapture; 8137 return workInProgress; 8138 } 8139 return null; 8140 } 8141 case HostRoot: 8142 { 8143 popHostContainer(workInProgress); 8144 popTopLevelContextObject(workInProgress); 8145 var _effectTag = workInProgress.effectTag; 8146 !((_effectTag & DidCapture) === NoEffect) ? reactProdInvariant('285') : void 0; 8147 workInProgress.effectTag = _effectTag & ~ShouldCapture | DidCapture; 8148 return workInProgress; 8149 } 8150 case HostComponent: 8151 { 8152 // TODO: popHydrationState 8153 popHostContext(workInProgress); 8154 return null; 8155 } 8156 case SuspenseComponent: 8157 { 8158 var _effectTag2 = workInProgress.effectTag; 8159 if (_effectTag2 & ShouldCapture) { 8160 workInProgress.effectTag = _effectTag2 & ~ShouldCapture | DidCapture; 8161 // Captured a suspense effect. Re-render the boundary. 8162 return workInProgress; 8163 } 8164 return null; 8165 } 8166 case DehydratedSuspenseComponent: 8167 { 8168 if (enableSuspenseServerRenderer) { 8169 // TODO: popHydrationState 8170 var _effectTag3 = workInProgress.effectTag; 8171 if (_effectTag3 & ShouldCapture) { 8172 workInProgress.effectTag = _effectTag3 & ~ShouldCapture | DidCapture; 8173 // Captured a suspense effect. Re-render the boundary. 8174 return workInProgress; 8175 } 8176 } 8177 return null; 8178 } 8179 case HostPortal: 8180 popHostContainer(workInProgress); 8181 return null; 8182 case ContextProvider: 8183 popProvider(workInProgress); 8184 return null; 8185 default: 8186 return null; 8187 } 8188 } 8189 8190 function unwindInterruptedWork(interruptedWork) { 8191 switch (interruptedWork.tag) { 8192 case ClassComponent: 8193 { 8194 var childContextTypes = interruptedWork.type.childContextTypes; 8195 if (childContextTypes !== null && childContextTypes !== undefined) { 8196 popContext(interruptedWork); 8197 } 8198 break; 8199 } 8200 case HostRoot: 8201 { 8202 popHostContainer(interruptedWork); 8203 popTopLevelContextObject(interruptedWork); 8204 break; 8205 } 8206 case HostComponent: 8207 { 8208 popHostContext(interruptedWork); 8209 break; 8210 } 8211 case HostPortal: 8212 popHostContainer(interruptedWork); 8213 break; 8214 case ContextProvider: 8215 popProvider(interruptedWork); 8216 break; 8217 default: 8218 break; 8219 } 8220 } 8221 8222 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; 8223 var ReactCurrentOwner$1 = ReactSharedInternals.ReactCurrentOwner; 8224 8225 8226 if (enableSchedulerTracing) { 8227 // Provide explicit error message when production+profiling bundle of e.g. react-dom 8228 // is used with production (non-profiling) bundle of scheduler/tracing 8229 !(__interactionsRef != null && __interactionsRef.current != null) ? reactProdInvariant('302') : void 0; 8230 } 8231 8232 var isWorking = false; 8233 8234 // The next work in progress fiber that we're currently working on. 8235 var nextUnitOfWork = null; 8236 var nextRoot = null; 8237 // The time at which we're currently rendering work. 8238 var nextRenderExpirationTime = NoWork; 8239 var nextLatestAbsoluteTimeoutMs = -1; 8240 var nextRenderDidError = false; 8241 8242 // The next fiber with an effect that we're currently committing. 8243 var nextEffect = null; 8244 8245 var isCommitting$1 = false; 8246 var rootWithPendingPassiveEffects = null; 8247 var passiveEffectCallbackHandle = null; 8248 var passiveEffectCallback = null; 8249 8250 var legacyErrorBoundariesThatAlreadyFailed = null; 8251 8252 // Used for performance tracking. 8253 var interruptedBy = null; 8254 8255 function resetStack() { 8256 if (nextUnitOfWork !== null) { 8257 var interruptedWork = nextUnitOfWork.return; 8258 while (interruptedWork !== null) { 8259 unwindInterruptedWork(interruptedWork); 8260 interruptedWork = interruptedWork.return; 8261 } 8262 } 8263 8264 nextRoot = null; 8265 nextRenderExpirationTime = NoWork; 8266 nextLatestAbsoluteTimeoutMs = -1; 8267 nextRenderDidError = false; 8268 nextUnitOfWork = null; 8269 } 8270 8271 function commitAllHostEffects() { 8272 while (nextEffect !== null) { 8273 recordEffect(); 8274 8275 var effectTag = nextEffect.effectTag; 8276 8277 if (effectTag & ContentReset) { 8278 commitResetTextContent(nextEffect); 8279 } 8280 8281 if (effectTag & Ref) { 8282 var current$$1 = nextEffect.alternate; 8283 if (current$$1 !== null) { 8284 commitDetachRef(current$$1); 8285 } 8286 } 8287 8288 // The following switch statement is only concerned about placement, 8289 // updates, and deletions. To avoid needing to add a case for every 8290 // possible bitmap value, we remove the secondary effects from the 8291 // effect tag and switch on that value. 8292 var primaryEffectTag = effectTag & (Placement | Update | Deletion); 8293 switch (primaryEffectTag) { 8294 case Placement: 8295 { 8296 commitPlacement(nextEffect); 8297 // Clear the "placement" from effect tag so that we know that this is inserted, before 8298 // any life-cycles like componentDidMount gets called. 8299 // TODO: findDOMNode doesn't rely on this any more but isMounted 8300 // does and isMounted is deprecated anyway so we should be able 8301 // to kill this. 8302 nextEffect.effectTag &= ~Placement; 8303 break; 8304 } 8305 case PlacementAndUpdate: 8306 { 8307 // Placement 8308 commitPlacement(nextEffect); 8309 // Clear the "placement" from effect tag so that we know that this is inserted, before 8310 // any life-cycles like componentDidMount gets called. 8311 nextEffect.effectTag &= ~Placement; 8312 8313 // Update 8314 var _current = nextEffect.alternate; 8315 commitWork(_current, nextEffect); 8316 break; 8317 } 8318 case Update: 8319 { 8320 var _current2 = nextEffect.alternate; 8321 commitWork(_current2, nextEffect); 8322 break; 8323 } 8324 case Deletion: 8325 { 8326 commitDeletion(nextEffect); 8327 break; 8328 } 8329 } 8330 nextEffect = nextEffect.nextEffect; 8331 } 8332 8333 8334 } 8335 8336 function commitBeforeMutationLifecycles() { 8337 while (nextEffect !== null) { 8338 var effectTag = nextEffect.effectTag; 8339 if (effectTag & Snapshot) { 8340 recordEffect(); 8341 var current$$1 = nextEffect.alternate; 8342 commitBeforeMutationLifeCycles(current$$1, nextEffect); 8343 } 8344 8345 nextEffect = nextEffect.nextEffect; 8346 } 8347 8348 8349 } 8350 8351 function commitAllLifeCycles(finishedRoot, committedExpirationTime) { 8352 while (nextEffect !== null) { 8353 var effectTag = nextEffect.effectTag; 8354 8355 if (effectTag & (Update | Callback)) { 8356 recordEffect(); 8357 var current$$1 = nextEffect.alternate; 8358 commitLifeCycles(finishedRoot, current$$1, nextEffect, committedExpirationTime); 8359 } 8360 8361 if (effectTag & Ref) { 8362 recordEffect(); 8363 commitAttachRef(nextEffect); 8364 } 8365 8366 if (effectTag & Passive) { 8367 rootWithPendingPassiveEffects = finishedRoot; 8368 } 8369 8370 nextEffect = nextEffect.nextEffect; 8371 } 8372 8373 } 8374 8375 function commitPassiveEffects(root, firstEffect) { 8376 rootWithPendingPassiveEffects = null; 8377 passiveEffectCallbackHandle = null; 8378 passiveEffectCallback = null; 8379 8380 // Set this to true to prevent re-entrancy 8381 var previousIsRendering = isRendering; 8382 isRendering = true; 8383 8384 var effect = firstEffect; 8385 do { 8386 if (effect.effectTag & Passive) { 8387 var didError = false; 8388 var error = void 0; 8389 { 8390 try { 8391 commitPassiveHookEffects(effect); 8392 } catch (e) { 8393 didError = true; 8394 error = e; 8395 } 8396 } 8397 if (didError) { 8398 captureCommitPhaseError(effect, error); 8399 } 8400 } 8401 effect = effect.nextEffect; 8402 } while (effect !== null); 8403 isRendering = previousIsRendering; 8404 8405 // Check if work was scheduled by one of the effects 8406 var rootExpirationTime = root.expirationTime; 8407 if (rootExpirationTime !== NoWork) { 8408 requestWork(root, rootExpirationTime); 8409 } 8410 // Flush any sync work that was scheduled by effects 8411 if (!isBatchingUpdates && !isRendering) { 8412 performSyncWork(); 8413 } 8414 } 8415 8416 function isAlreadyFailedLegacyErrorBoundary(instance) { 8417 return legacyErrorBoundariesThatAlreadyFailed !== null && legacyErrorBoundariesThatAlreadyFailed.has(instance); 8418 } 8419 8420 function markLegacyErrorBoundaryAsFailed(instance) { 8421 if (legacyErrorBoundariesThatAlreadyFailed === null) { 8422 legacyErrorBoundariesThatAlreadyFailed = new Set([instance]); 8423 } else { 8424 legacyErrorBoundariesThatAlreadyFailed.add(instance); 8425 } 8426 } 8427 8428 function flushPassiveEffects$1() { 8429 if (passiveEffectCallbackHandle !== null) { 8430 cancelPassiveEffects(passiveEffectCallbackHandle); 8431 } 8432 if (passiveEffectCallback !== null) { 8433 // We call the scheduled callback instead of commitPassiveEffects directly 8434 // to ensure tracing works correctly. 8435 passiveEffectCallback(); 8436 } 8437 } 8438 8439 function commitRoot(root, finishedWork) { 8440 isWorking = true; 8441 isCommitting$1 = true; 8442 startCommitTimer(); 8443 8444 !(root.current !== finishedWork) ? reactProdInvariant('177') : void 0; 8445 var committedExpirationTime = root.pendingCommitExpirationTime; 8446 !(committedExpirationTime !== NoWork) ? reactProdInvariant('261') : void 0; 8447 root.pendingCommitExpirationTime = NoWork; 8448 8449 // Update the pending priority levels to account for the work that we are 8450 // about to commit. This needs to happen before calling the lifecycles, since 8451 // they may schedule additional updates. 8452 var updateExpirationTimeBeforeCommit = finishedWork.expirationTime; 8453 var childExpirationTimeBeforeCommit = finishedWork.childExpirationTime; 8454 var earliestRemainingTimeBeforeCommit = childExpirationTimeBeforeCommit > updateExpirationTimeBeforeCommit ? childExpirationTimeBeforeCommit : updateExpirationTimeBeforeCommit; 8455 markCommittedPriorityLevels(root, earliestRemainingTimeBeforeCommit); 8456 8457 var prevInteractions = null; 8458 if (enableSchedulerTracing) { 8459 // Restore any pending interactions at this point, 8460 // So that cascading work triggered during the render phase will be accounted for. 8461 prevInteractions = __interactionsRef.current; 8462 __interactionsRef.current = root.memoizedInteractions; 8463 } 8464 8465 // Reset this to null before calling lifecycles 8466 ReactCurrentOwner$1.current = null; 8467 8468 var firstEffect = void 0; 8469 if (finishedWork.effectTag > PerformedWork) { 8470 // A fiber's effect list consists only of its children, not itself. So if 8471 // the root has an effect, we need to add it to the end of the list. The 8472 // resulting list is the set that would belong to the root's parent, if 8473 // it had one; that is, all the effects in the tree including the root. 8474 if (finishedWork.lastEffect !== null) { 8475 finishedWork.lastEffect.nextEffect = finishedWork; 8476 firstEffect = finishedWork.firstEffect; 8477 } else { 8478 firstEffect = finishedWork; 8479 } 8480 } else { 8481 // There is no effect on the root. 8482 firstEffect = finishedWork.firstEffect; 8483 } 8484 8485 prepareForCommit(root.containerInfo); 8486 8487 // Invoke instances of getSnapshotBeforeUpdate before mutation. 8488 nextEffect = firstEffect; 8489 startCommitSnapshotEffectsTimer(); 8490 while (nextEffect !== null) { 8491 var didError = false; 8492 var error = void 0; 8493 { 8494 try { 8495 commitBeforeMutationLifecycles(); 8496 } catch (e) { 8497 didError = true; 8498 error = e; 8499 } 8500 } 8501 if (didError) { 8502 !(nextEffect !== null) ? reactProdInvariant('178') : void 0; 8503 captureCommitPhaseError(nextEffect, error); 8504 // Clean-up 8505 if (nextEffect !== null) { 8506 nextEffect = nextEffect.nextEffect; 8507 } 8508 } 8509 } 8510 stopCommitSnapshotEffectsTimer(); 8511 8512 if (enableProfilerTimer) { 8513 // Mark the current commit time to be shared by all Profilers in this batch. 8514 // This enables them to be grouped later. 8515 recordCommitTime(); 8516 } 8517 8518 // Commit all the side-effects within a tree. We'll do this in two passes. 8519 // The first pass performs all the host insertions, updates, deletions and 8520 // ref unmounts. 8521 nextEffect = firstEffect; 8522 startCommitHostEffectsTimer(); 8523 while (nextEffect !== null) { 8524 var _didError = false; 8525 var _error = void 0; 8526 { 8527 try { 8528 commitAllHostEffects(); 8529 } catch (e) { 8530 _didError = true; 8531 _error = e; 8532 } 8533 } 8534 if (_didError) { 8535 !(nextEffect !== null) ? reactProdInvariant('178') : void 0; 8536 captureCommitPhaseError(nextEffect, _error); 8537 // Clean-up 8538 if (nextEffect !== null) { 8539 nextEffect = nextEffect.nextEffect; 8540 } 8541 } 8542 } 8543 stopCommitHostEffectsTimer(); 8544 8545 resetAfterCommit(root.containerInfo); 8546 8547 // The work-in-progress tree is now the current tree. This must come after 8548 // the first pass of the commit phase, so that the previous tree is still 8549 // current during componentWillUnmount, but before the second pass, so that 8550 // the finished work is current during componentDidMount/Update. 8551 root.current = finishedWork; 8552 8553 // In the second pass we'll perform all life-cycles and ref callbacks. 8554 // Life-cycles happen as a separate pass so that all placements, updates, 8555 // and deletions in the entire tree have already been invoked. 8556 // This pass also triggers any renderer-specific initial effects. 8557 nextEffect = firstEffect; 8558 startCommitLifeCyclesTimer(); 8559 while (nextEffect !== null) { 8560 var _didError2 = false; 8561 var _error2 = void 0; 8562 { 8563 try { 8564 commitAllLifeCycles(root, committedExpirationTime); 8565 } catch (e) { 8566 _didError2 = true; 8567 _error2 = e; 8568 } 8569 } 8570 if (_didError2) { 8571 !(nextEffect !== null) ? reactProdInvariant('178') : void 0; 8572 captureCommitPhaseError(nextEffect, _error2); 8573 if (nextEffect !== null) { 8574 nextEffect = nextEffect.nextEffect; 8575 } 8576 } 8577 } 8578 8579 if (firstEffect !== null && rootWithPendingPassiveEffects !== null) { 8580 // This commit included a passive effect. These do not need to fire until 8581 // after the next paint. Schedule an callback to fire them in an async 8582 // event. To ensure serial execution, the callback will be flushed early if 8583 // we enter rootWithPendingPassiveEffects commit phase before then. 8584 var callback = commitPassiveEffects.bind(null, root, firstEffect); 8585 if (enableSchedulerTracing) { 8586 // TODO: Avoid this extra callback by mutating the tracing ref directly, 8587 // like we do at the beginning of commitRoot. I've opted not to do that 8588 // here because that code is still in flux. 8589 callback = unstable_wrap(callback); 8590 } 8591 passiveEffectCallbackHandle = unstable_runWithPriority(unstable_NormalPriority, function () { 8592 return schedulePassiveEffects(callback); 8593 }); 8594 passiveEffectCallback = callback; 8595 } 8596 8597 isCommitting$1 = false; 8598 isWorking = false; 8599 stopCommitLifeCyclesTimer(); 8600 stopCommitTimer(); 8601 onCommitRoot(finishedWork.stateNode); 8602 var updateExpirationTimeAfterCommit = finishedWork.expirationTime; 8603 var childExpirationTimeAfterCommit = finishedWork.childExpirationTime; 8604 var earliestRemainingTimeAfterCommit = childExpirationTimeAfterCommit > updateExpirationTimeAfterCommit ? childExpirationTimeAfterCommit : updateExpirationTimeAfterCommit; 8605 if (earliestRemainingTimeAfterCommit === NoWork) { 8606 // If there's no remaining work, we can clear the set of already failed 8607 // error boundaries. 8608 legacyErrorBoundariesThatAlreadyFailed = null; 8609 } 8610 onCommit(root, earliestRemainingTimeAfterCommit); 8611 8612 if (enableSchedulerTracing) { 8613 __interactionsRef.current = prevInteractions; 8614 8615 var subscriber = void 0; 8616 8617 try { 8618 subscriber = __subscriberRef.current; 8619 if (subscriber !== null && root.memoizedInteractions.size > 0) { 8620 var threadID = computeThreadID(committedExpirationTime, root.interactionThreadID); 8621 subscriber.onWorkStopped(root.memoizedInteractions, threadID); 8622 } 8623 } catch (error) { 8624 // It's not safe for commitRoot() to throw. 8625 // Store the error for now and we'll re-throw in finishRendering(). 8626 if (!hasUnhandledError) { 8627 hasUnhandledError = true; 8628 unhandledError = error; 8629 } 8630 } finally { 8631 // Clear completed interactions from the pending Map. 8632 // Unless the render was suspended or cascading work was scheduled, 8633 // In which case– leave pending interactions until the subsequent render. 8634 var pendingInteractionMap = root.pendingInteractionMap; 8635 pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { 8636 // Only decrement the pending interaction count if we're done. 8637 // If there's still work at the current priority, 8638 // That indicates that we are waiting for suspense data. 8639 if (scheduledExpirationTime > earliestRemainingTimeAfterCommit) { 8640 pendingInteractionMap.delete(scheduledExpirationTime); 8641 8642 scheduledInteractions.forEach(function (interaction) { 8643 interaction.__count--; 8644 8645 if (subscriber !== null && interaction.__count === 0) { 8646 try { 8647 subscriber.onInteractionScheduledWorkCompleted(interaction); 8648 } catch (error) { 8649 // It's not safe for commitRoot() to throw. 8650 // Store the error for now and we'll re-throw in finishRendering(). 8651 if (!hasUnhandledError) { 8652 hasUnhandledError = true; 8653 unhandledError = error; 8654 } 8655 } 8656 } 8657 }); 8658 } 8659 }); 8660 } 8661 } 8662 } 8663 8664 function resetChildExpirationTime(workInProgress, renderTime) { 8665 if (renderTime !== Never && workInProgress.childExpirationTime === Never) { 8666 // The children of this component are hidden. Don't bubble their 8667 // expiration times. 8668 return; 8669 } 8670 8671 var newChildExpirationTime = NoWork; 8672 8673 // Bubble up the earliest expiration time. 8674 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 8675 // We're in profiling mode. 8676 // Let's use this same traversal to update the render durations. 8677 var actualDuration = workInProgress.actualDuration; 8678 var treeBaseDuration = workInProgress.selfBaseDuration; 8679 8680 // When a fiber is cloned, its actualDuration is reset to 0. 8681 // This value will only be updated if work is done on the fiber (i.e. it doesn't bailout). 8682 // When work is done, it should bubble to the parent's actualDuration. 8683 // If the fiber has not been cloned though, (meaning no work was done), 8684 // Then this value will reflect the amount of time spent working on a previous render. 8685 // In that case it should not bubble. 8686 // We determine whether it was cloned by comparing the child pointer. 8687 var shouldBubbleActualDurations = workInProgress.alternate === null || workInProgress.child !== workInProgress.alternate.child; 8688 8689 var child = workInProgress.child; 8690 while (child !== null) { 8691 var childUpdateExpirationTime = child.expirationTime; 8692 var childChildExpirationTime = child.childExpirationTime; 8693 if (childUpdateExpirationTime > newChildExpirationTime) { 8694 newChildExpirationTime = childUpdateExpirationTime; 8695 } 8696 if (childChildExpirationTime > newChildExpirationTime) { 8697 newChildExpirationTime = childChildExpirationTime; 8698 } 8699 if (shouldBubbleActualDurations) { 8700 actualDuration += child.actualDuration; 8701 } 8702 treeBaseDuration += child.treeBaseDuration; 8703 child = child.sibling; 8704 } 8705 workInProgress.actualDuration = actualDuration; 8706 workInProgress.treeBaseDuration = treeBaseDuration; 8707 } else { 8708 var _child = workInProgress.child; 8709 while (_child !== null) { 8710 var _childUpdateExpirationTime = _child.expirationTime; 8711 var _childChildExpirationTime = _child.childExpirationTime; 8712 if (_childUpdateExpirationTime > newChildExpirationTime) { 8713 newChildExpirationTime = _childUpdateExpirationTime; 8714 } 8715 if (_childChildExpirationTime > newChildExpirationTime) { 8716 newChildExpirationTime = _childChildExpirationTime; 8717 } 8718 _child = _child.sibling; 8719 } 8720 } 8721 8722 workInProgress.childExpirationTime = newChildExpirationTime; 8723 } 8724 8725 function completeUnitOfWork(workInProgress) { 8726 // Attempt to complete the current unit of work, then move to the 8727 // next sibling. If there are no more siblings, return to the 8728 // parent fiber. 8729 while (true) { 8730 // The current, flushed, state of this fiber is the alternate. 8731 // Ideally nothing should rely on this, but relying on it here 8732 // means that we don't need an additional field on the work in 8733 // progress. 8734 var current$$1 = workInProgress.alternate; 8735 var returnFiber = workInProgress.return; 8736 var siblingFiber = workInProgress.sibling; 8737 8738 if ((workInProgress.effectTag & Incomplete) === NoEffect) { 8739 nextUnitOfWork = workInProgress; 8740 if (enableProfilerTimer) { 8741 if (workInProgress.mode & ProfileMode) { 8742 startProfilerTimer(workInProgress); 8743 } 8744 nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); 8745 if (workInProgress.mode & ProfileMode) { 8746 // Update render duration assuming we didn't error. 8747 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); 8748 } 8749 } else { 8750 nextUnitOfWork = completeWork(current$$1, workInProgress, nextRenderExpirationTime); 8751 } 8752 stopWorkTimer(workInProgress); 8753 resetChildExpirationTime(workInProgress, nextRenderExpirationTime); 8754 if (nextUnitOfWork !== null) { 8755 // Completing this fiber spawned new work. Work on that next. 8756 return nextUnitOfWork; 8757 } 8758 8759 if (returnFiber !== null && 8760 // Do not append effects to parents if a sibling failed to complete 8761 (returnFiber.effectTag & Incomplete) === NoEffect) { 8762 // Append all the effects of the subtree and this fiber onto the effect 8763 // list of the parent. The completion order of the children affects the 8764 // side-effect order. 8765 if (returnFiber.firstEffect === null) { 8766 returnFiber.firstEffect = workInProgress.firstEffect; 8767 } 8768 if (workInProgress.lastEffect !== null) { 8769 if (returnFiber.lastEffect !== null) { 8770 returnFiber.lastEffect.nextEffect = workInProgress.firstEffect; 8771 } 8772 returnFiber.lastEffect = workInProgress.lastEffect; 8773 } 8774 8775 // If this fiber had side-effects, we append it AFTER the children's 8776 // side-effects. We can perform certain side-effects earlier if 8777 // needed, by doing multiple passes over the effect list. We don't want 8778 // to schedule our own side-effect on our own list because if end up 8779 // reusing children we'll schedule this effect onto itself since we're 8780 // at the end. 8781 var effectTag = workInProgress.effectTag; 8782 // Skip both NoWork and PerformedWork tags when creating the effect list. 8783 // PerformedWork effect is read by React DevTools but shouldn't be committed. 8784 if (effectTag > PerformedWork) { 8785 if (returnFiber.lastEffect !== null) { 8786 returnFiber.lastEffect.nextEffect = workInProgress; 8787 } else { 8788 returnFiber.firstEffect = workInProgress; 8789 } 8790 returnFiber.lastEffect = workInProgress; 8791 } 8792 } 8793 8794 if (siblingFiber !== null) { 8795 // If there is more work to do in this returnFiber, do that next. 8796 return siblingFiber; 8797 } else if (returnFiber !== null) { 8798 // If there's no more work in this returnFiber. Complete the returnFiber. 8799 workInProgress = returnFiber; 8800 continue; 8801 } else { 8802 // We've reached the root. 8803 return null; 8804 } 8805 } else { 8806 if (enableProfilerTimer && workInProgress.mode & ProfileMode) { 8807 // Record the render duration for the fiber that errored. 8808 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, false); 8809 8810 // Include the time spent working on failed children before continuing. 8811 var actualDuration = workInProgress.actualDuration; 8812 var child = workInProgress.child; 8813 while (child !== null) { 8814 actualDuration += child.actualDuration; 8815 child = child.sibling; 8816 } 8817 workInProgress.actualDuration = actualDuration; 8818 } 8819 8820 // This fiber did not complete because something threw. Pop values off 8821 // the stack without entering the complete phase. If this is a boundary, 8822 // capture values if possible. 8823 var next = unwindWork(workInProgress, nextRenderExpirationTime); 8824 // Because this fiber did not complete, don't reset its expiration time. 8825 if (workInProgress.effectTag & DidCapture) { 8826 // Restarting an error boundary 8827 stopFailedWorkTimer(workInProgress); 8828 } else { 8829 stopWorkTimer(workInProgress); 8830 } 8831 8832 if (next !== null) { 8833 stopWorkTimer(workInProgress); 8834 next.effectTag &= HostEffectMask; 8835 return next; 8836 } 8837 8838 if (returnFiber !== null) { 8839 // Mark the parent fiber as incomplete and clear its effect list. 8840 returnFiber.firstEffect = returnFiber.lastEffect = null; 8841 returnFiber.effectTag |= Incomplete; 8842 } 8843 8844 if (siblingFiber !== null) { 8845 // If there is more work to do in this returnFiber, do that next. 8846 return siblingFiber; 8847 } else if (returnFiber !== null) { 8848 // If there's no more work in this returnFiber. Complete the returnFiber. 8849 workInProgress = returnFiber; 8850 continue; 8851 } else { 8852 return null; 8853 } 8854 } 8855 } 8856 8857 // Without this explicit null return Flow complains of invalid return type 8858 // TODO Remove the above while(true) loop 8859 // eslint-disable-next-line no-unreachable 8860 return null; 8861 } 8862 8863 function performUnitOfWork(workInProgress) { 8864 // The current, flushed, state of this fiber is the alternate. 8865 // Ideally nothing should rely on this, but relying on it here 8866 // means that we don't need an additional field on the work in 8867 // progress. 8868 var current$$1 = workInProgress.alternate; 8869 8870 // See if beginning this work spawns more work. 8871 startWorkTimer(workInProgress); 8872 var next = void 0; 8873 if (enableProfilerTimer) { 8874 if (workInProgress.mode & ProfileMode) { 8875 startProfilerTimer(workInProgress); 8876 } 8877 8878 next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); 8879 workInProgress.memoizedProps = workInProgress.pendingProps; 8880 8881 if (workInProgress.mode & ProfileMode) { 8882 // Record the render duration assuming we didn't bailout (or error). 8883 stopProfilerTimerIfRunningAndRecordDelta(workInProgress, true); 8884 } 8885 } else { 8886 next = beginWork(current$$1, workInProgress, nextRenderExpirationTime); 8887 workInProgress.memoizedProps = workInProgress.pendingProps; 8888 } 8889 8890 if (next === null) { 8891 // If this doesn't spawn new work, complete the current work. 8892 next = completeUnitOfWork(workInProgress); 8893 } 8894 8895 ReactCurrentOwner$1.current = null; 8896 8897 return next; 8898 } 8899 8900 function workLoop(isYieldy) { 8901 if (!isYieldy) { 8902 // Flush work without yielding 8903 while (nextUnitOfWork !== null) { 8904 nextUnitOfWork = performUnitOfWork(nextUnitOfWork); 8905 } 8906 } else { 8907 // Flush asynchronous work until there's a higher priority event 8908 while (nextUnitOfWork !== null && !shouldYieldToRenderer()) { 8909 nextUnitOfWork = performUnitOfWork(nextUnitOfWork); 8910 } 8911 } 8912 } 8913 8914 function renderRoot(root, isYieldy) { 8915 !!isWorking ? reactProdInvariant('243') : void 0; 8916 8917 flushPassiveEffects$1(); 8918 8919 isWorking = true; 8920 var previousDispatcher = ReactCurrentDispatcher.current; 8921 ReactCurrentDispatcher.current = ContextOnlyDispatcher; 8922 8923 var expirationTime = root.nextExpirationTimeToWorkOn; 8924 8925 // Check if we're starting from a fresh stack, or if we're resuming from 8926 // previously yielded work. 8927 if (expirationTime !== nextRenderExpirationTime || root !== nextRoot || nextUnitOfWork === null) { 8928 // Reset the stack and start working from the root. 8929 resetStack(); 8930 nextRoot = root; 8931 nextRenderExpirationTime = expirationTime; 8932 nextUnitOfWork = createWorkInProgress(nextRoot.current, null, nextRenderExpirationTime); 8933 root.pendingCommitExpirationTime = NoWork; 8934 8935 if (enableSchedulerTracing) { 8936 // Determine which interactions this batch of work currently includes, 8937 // So that we can accurately attribute time spent working on it, 8938 var interactions = new Set(); 8939 root.pendingInteractionMap.forEach(function (scheduledInteractions, scheduledExpirationTime) { 8940 if (scheduledExpirationTime >= expirationTime) { 8941 scheduledInteractions.forEach(function (interaction) { 8942 return interactions.add(interaction); 8943 }); 8944 } 8945 }); 8946 8947 // Store the current set of interactions on the FiberRoot for a few reasons: 8948 // We can re-use it in hot functions like renderRoot() without having to recalculate it. 8949 // We will also use it in commitWork() to pass to any Profiler onRender() hooks. 8950 // This also provides DevTools with a way to access it when the onCommitRoot() hook is called. 8951 root.memoizedInteractions = interactions; 8952 8953 if (interactions.size > 0) { 8954 var subscriber = __subscriberRef.current; 8955 if (subscriber !== null) { 8956 var threadID = computeThreadID(expirationTime, root.interactionThreadID); 8957 try { 8958 subscriber.onWorkStarted(interactions, threadID); 8959 } catch (error) { 8960 // Work thrown by an interaction tracing subscriber should be rethrown, 8961 // But only once it's safe (to avoid leaving the scheduler in an invalid state). 8962 // Store the error for now and we'll re-throw in finishRendering(). 8963 if (!hasUnhandledError) { 8964 hasUnhandledError = true; 8965 unhandledError = error; 8966 } 8967 } 8968 } 8969 } 8970 } 8971 } 8972 8973 var prevInteractions = null; 8974 if (enableSchedulerTracing) { 8975 // We're about to start new traced work. 8976 // Restore pending interactions so cascading work triggered during the render phase will be accounted for. 8977 prevInteractions = __interactionsRef.current; 8978 __interactionsRef.current = root.memoizedInteractions; 8979 } 8980 8981 var didFatal = false; 8982 8983 startWorkLoopTimer(nextUnitOfWork); 8984 8985 do { 8986 try { 8987 workLoop(isYieldy); 8988 } catch (thrownValue) { 8989 resetContextDependences(); 8990 resetHooks(); 8991 8992 // Reset in case completion throws. 8993 // This is only used in DEV and when replaying is on. 8994 if (nextUnitOfWork === null) { 8995 // This is a fatal error. 8996 didFatal = true; 8997 onUncaughtError(thrownValue); 8998 } else { 8999 if (enableProfilerTimer && nextUnitOfWork.mode & ProfileMode) { 9000 // Record the time spent rendering before an error was thrown. 9001 // This avoids inaccurate Profiler durations in the case of a suspended render. 9002 stopProfilerTimerIfRunningAndRecordDelta(nextUnitOfWork, true); 9003 } 9004 9005 !(nextUnitOfWork !== null) ? reactProdInvariant('271') : void 0; 9006 9007 var sourceFiber = nextUnitOfWork; 9008 var returnFiber = sourceFiber.return; 9009 if (returnFiber === null) { 9010 // This is the root. The root could capture its own errors. However, 9011 // we don't know if it errors before or after we pushed the host 9012 // context. This information is needed to avoid a stack mismatch. 9013 // Because we're not sure, treat this as a fatal error. We could track 9014 // which phase it fails in, but doesn't seem worth it. At least 9015 // for now. 9016 didFatal = true; 9017 onUncaughtError(thrownValue); 9018 } else { 9019 throwException(root, returnFiber, sourceFiber, thrownValue, nextRenderExpirationTime); 9020 nextUnitOfWork = completeUnitOfWork(sourceFiber); 9021 continue; 9022 } 9023 } 9024 } 9025 break; 9026 } while (true); 9027 9028 if (enableSchedulerTracing) { 9029 // Traced work is done for now; restore the previous interactions. 9030 __interactionsRef.current = prevInteractions; 9031 } 9032 9033 // We're done performing work. Time to clean up. 9034 isWorking = false; 9035 ReactCurrentDispatcher.current = previousDispatcher; 9036 resetContextDependences(); 9037 resetHooks(); 9038 9039 // Yield back to main thread. 9040 if (didFatal) { 9041 var _didCompleteRoot = false; 9042 stopWorkLoopTimer(interruptedBy, _didCompleteRoot); 9043 interruptedBy = null; 9044 // There was a fatal error. 9045 nextRoot = null; 9046 onFatal(root); 9047 return; 9048 } 9049 9050 if (nextUnitOfWork !== null) { 9051 // There's still remaining async work in this tree, but we ran out of time 9052 // in the current frame. Yield back to the renderer. Unless we're 9053 // interrupted by a higher priority update, we'll continue later from where 9054 // we left off. 9055 var _didCompleteRoot2 = false; 9056 stopWorkLoopTimer(interruptedBy, _didCompleteRoot2); 9057 interruptedBy = null; 9058 onYield(root); 9059 return; 9060 } 9061 9062 // We completed the whole tree. 9063 var didCompleteRoot = true; 9064 stopWorkLoopTimer(interruptedBy, didCompleteRoot); 9065 var rootWorkInProgress = root.current.alternate; 9066 !(rootWorkInProgress !== null) ? reactProdInvariant('281') : void 0; 9067 9068 // `nextRoot` points to the in-progress root. A non-null value indicates 9069 // that we're in the middle of an async render. Set it to null to indicate 9070 // there's no more work to be done in the current batch. 9071 nextRoot = null; 9072 interruptedBy = null; 9073 9074 if (nextRenderDidError) { 9075 // There was an error 9076 if (hasLowerPriorityWork(root, expirationTime)) { 9077 // There's lower priority work. If so, it may have the effect of fixing 9078 // the exception that was just thrown. Exit without committing. This is 9079 // similar to a suspend, but without a timeout because we're not waiting 9080 // for a promise to resolve. React will restart at the lower 9081 // priority level. 9082 markSuspendedPriorityLevel(root, expirationTime); 9083 var suspendedExpirationTime = expirationTime; 9084 var rootExpirationTime = root.expirationTime; 9085 onSuspend(root, rootWorkInProgress, suspendedExpirationTime, rootExpirationTime, -1 // Indicates no timeout 9086 ); 9087 return; 9088 } else if ( 9089 // There's no lower priority work, but we're rendering asynchronously. 9090 // Synchronously attempt to render the same level one more time. This is 9091 // similar to a suspend, but without a timeout because we're not waiting 9092 // for a promise to resolve. 9093 !root.didError && isYieldy) { 9094 root.didError = true; 9095 var _suspendedExpirationTime = root.nextExpirationTimeToWorkOn = expirationTime; 9096 var _rootExpirationTime = root.expirationTime = Sync; 9097 onSuspend(root, rootWorkInProgress, _suspendedExpirationTime, _rootExpirationTime, -1 // Indicates no timeout 9098 ); 9099 return; 9100 } 9101 } 9102 9103 if (isYieldy && nextLatestAbsoluteTimeoutMs !== -1) { 9104 // The tree was suspended. 9105 var _suspendedExpirationTime2 = expirationTime; 9106 markSuspendedPriorityLevel(root, _suspendedExpirationTime2); 9107 9108 // Find the earliest uncommitted expiration time in the tree, including 9109 // work that is suspended. The timeout threshold cannot be longer than 9110 // the overall expiration. 9111 var earliestExpirationTime = findEarliestOutstandingPriorityLevel(root, expirationTime); 9112 var earliestExpirationTimeMs = expirationTimeToMs(earliestExpirationTime); 9113 if (earliestExpirationTimeMs < nextLatestAbsoluteTimeoutMs) { 9114 nextLatestAbsoluteTimeoutMs = earliestExpirationTimeMs; 9115 } 9116 9117 // Subtract the current time from the absolute timeout to get the number 9118 // of milliseconds until the timeout. In other words, convert an absolute 9119 // timestamp to a relative time. This is the value that is passed 9120 // to `setTimeout`. 9121 var currentTimeMs = expirationTimeToMs(requestCurrentTime()); 9122 var msUntilTimeout = nextLatestAbsoluteTimeoutMs - currentTimeMs; 9123 msUntilTimeout = msUntilTimeout < 0 ? 0 : msUntilTimeout; 9124 9125 // TODO: Account for the Just Noticeable Difference 9126 9127 var _rootExpirationTime2 = root.expirationTime; 9128 onSuspend(root, rootWorkInProgress, _suspendedExpirationTime2, _rootExpirationTime2, msUntilTimeout); 9129 return; 9130 } 9131 9132 // Ready to commit. 9133 onComplete(root, rootWorkInProgress, expirationTime); 9134 } 9135 9136 function captureCommitPhaseError(sourceFiber, value) { 9137 var expirationTime = Sync; 9138 var fiber = sourceFiber.return; 9139 while (fiber !== null) { 9140 switch (fiber.tag) { 9141 case ClassComponent: 9142 var ctor = fiber.type; 9143 var instance = fiber.stateNode; 9144 if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function' && !isAlreadyFailedLegacyErrorBoundary(instance)) { 9145 var errorInfo = createCapturedValue(value, sourceFiber); 9146 var update = createClassErrorUpdate(fiber, errorInfo, expirationTime); 9147 enqueueUpdate(fiber, update); 9148 scheduleWork(fiber, expirationTime); 9149 return; 9150 } 9151 break; 9152 case HostRoot: 9153 { 9154 var _errorInfo = createCapturedValue(value, sourceFiber); 9155 var _update = createRootErrorUpdate(fiber, _errorInfo, expirationTime); 9156 enqueueUpdate(fiber, _update); 9157 scheduleWork(fiber, expirationTime); 9158 return; 9159 } 9160 } 9161 fiber = fiber.return; 9162 } 9163 9164 if (sourceFiber.tag === HostRoot) { 9165 // Error was thrown at the root. There is no parent, so the root 9166 // itself should capture it. 9167 var rootFiber = sourceFiber; 9168 var _errorInfo2 = createCapturedValue(value, rootFiber); 9169 var _update2 = createRootErrorUpdate(rootFiber, _errorInfo2, expirationTime); 9170 enqueueUpdate(rootFiber, _update2); 9171 scheduleWork(rootFiber, expirationTime); 9172 } 9173 } 9174 9175 function computeThreadID(expirationTime, interactionThreadID) { 9176 // Interaction threads are unique per root and expiration time. 9177 return expirationTime * 1000 + interactionThreadID; 9178 } 9179 9180 function computeExpirationForFiber(currentTime, fiber) { 9181 var priorityLevel = unstable_getCurrentPriorityLevel(); 9182 9183 var expirationTime = void 0; 9184 if ((fiber.mode & ConcurrentMode) === NoContext) { 9185 // Outside of concurrent mode, updates are always synchronous. 9186 expirationTime = Sync; 9187 } else if (isWorking && !isCommitting$1) { 9188 // During render phase, updates expire during as the current render. 9189 expirationTime = nextRenderExpirationTime; 9190 } else { 9191 switch (priorityLevel) { 9192 case unstable_ImmediatePriority: 9193 expirationTime = Sync; 9194 break; 9195 case unstable_UserBlockingPriority: 9196 expirationTime = computeInteractiveExpiration(currentTime); 9197 break; 9198 case unstable_NormalPriority: 9199 // This is a normal, concurrent update 9200 expirationTime = computeAsyncExpiration(currentTime); 9201 break; 9202 case unstable_LowPriority: 9203 case unstable_IdlePriority: 9204 expirationTime = Never; 9205 break; 9206 default: 9207 reactProdInvariant('313'); 9208 } 9209 9210 // If we're in the middle of rendering a tree, do not update at the same 9211 // expiration time that is already rendering. 9212 if (nextRoot !== null && expirationTime === nextRenderExpirationTime) { 9213 expirationTime -= 1; 9214 } 9215 } 9216 9217 // Keep track of the lowest pending interactive expiration time. This 9218 // allows us to synchronously flush all interactive updates 9219 // when needed. 9220 // TODO: Move this to renderer? 9221 return expirationTime; 9222 } 9223 9224 function renderDidSuspend(root, absoluteTimeoutMs, suspendedTime) { 9225 // Schedule the timeout. 9226 if (absoluteTimeoutMs >= 0 && nextLatestAbsoluteTimeoutMs < absoluteTimeoutMs) { 9227 nextLatestAbsoluteTimeoutMs = absoluteTimeoutMs; 9228 } 9229 } 9230 9231 function renderDidError() { 9232 nextRenderDidError = true; 9233 } 9234 9235 function pingSuspendedRoot(root, thenable, pingTime) { 9236 // A promise that previously suspended React from committing has resolved. 9237 // If React is still suspended, try again at the previous level (pingTime). 9238 9239 var pingCache = root.pingCache; 9240 if (pingCache !== null) { 9241 // The thenable resolved, so we no longer need to memoize, because it will 9242 // never be thrown again. 9243 pingCache.delete(thenable); 9244 } 9245 9246 if (nextRoot !== null && nextRenderExpirationTime === pingTime) { 9247 // Received a ping at the same priority level at which we're currently 9248 // rendering. Restart from the root. 9249 nextRoot = null; 9250 } else { 9251 // Confirm that the root is still suspended at this level. Otherwise exit. 9252 if (isPriorityLevelSuspended(root, pingTime)) { 9253 // Ping at the original level 9254 markPingedPriorityLevel(root, pingTime); 9255 var rootExpirationTime = root.expirationTime; 9256 if (rootExpirationTime !== NoWork) { 9257 requestWork(root, rootExpirationTime); 9258 } 9259 } 9260 } 9261 } 9262 9263 function retryTimedOutBoundary(boundaryFiber, thenable) { 9264 // The boundary fiber (a Suspense component) previously timed out and was 9265 // rendered in its fallback state. One of the promises that suspended it has 9266 // resolved, which means at least part of the tree was likely unblocked. Try 9267 var retryCache = void 0; 9268 if (enableSuspenseServerRenderer) { 9269 switch (boundaryFiber.tag) { 9270 case SuspenseComponent: 9271 retryCache = boundaryFiber.stateNode; 9272 break; 9273 case DehydratedSuspenseComponent: 9274 retryCache = boundaryFiber.memoizedState; 9275 break; 9276 default: 9277 reactProdInvariant('314'); 9278 } 9279 } else { 9280 retryCache = boundaryFiber.stateNode; 9281 } 9282 if (retryCache !== null) { 9283 // The thenable resolved, so we no longer need to memoize, because it will 9284 // never be thrown again. 9285 retryCache.delete(thenable); 9286 } 9287 9288 var currentTime = requestCurrentTime(); 9289 var retryTime = computeExpirationForFiber(currentTime, boundaryFiber); 9290 var root = scheduleWorkToRoot(boundaryFiber, retryTime); 9291 if (root !== null) { 9292 markPendingPriorityLevel(root, retryTime); 9293 var rootExpirationTime = root.expirationTime; 9294 if (rootExpirationTime !== NoWork) { 9295 requestWork(root, rootExpirationTime); 9296 } 9297 } 9298 } 9299 9300 function scheduleWorkToRoot(fiber, expirationTime) { 9301 recordScheduleUpdate(); 9302 9303 if (fiber.expirationTime < expirationTime) { 9304 fiber.expirationTime = expirationTime; 9305 } 9306 var alternate = fiber.alternate; 9307 if (alternate !== null && alternate.expirationTime < expirationTime) { 9308 alternate.expirationTime = expirationTime; 9309 } 9310 // Walk the parent path to the root and update the child expiration time. 9311 var node = fiber.return; 9312 var root = null; 9313 if (node === null && fiber.tag === HostRoot) { 9314 root = fiber.stateNode; 9315 } else { 9316 while (node !== null) { 9317 alternate = node.alternate; 9318 if (node.childExpirationTime < expirationTime) { 9319 node.childExpirationTime = expirationTime; 9320 if (alternate !== null && alternate.childExpirationTime < expirationTime) { 9321 alternate.childExpirationTime = expirationTime; 9322 } 9323 } else if (alternate !== null && alternate.childExpirationTime < expirationTime) { 9324 alternate.childExpirationTime = expirationTime; 9325 } 9326 if (node.return === null && node.tag === HostRoot) { 9327 root = node.stateNode; 9328 break; 9329 } 9330 node = node.return; 9331 } 9332 } 9333 9334 if (enableSchedulerTracing) { 9335 if (root !== null) { 9336 var interactions = __interactionsRef.current; 9337 if (interactions.size > 0) { 9338 var pendingInteractionMap = root.pendingInteractionMap; 9339 var pendingInteractions = pendingInteractionMap.get(expirationTime); 9340 if (pendingInteractions != null) { 9341 interactions.forEach(function (interaction) { 9342 if (!pendingInteractions.has(interaction)) { 9343 // Update the pending async work count for previously unscheduled interaction. 9344 interaction.__count++; 9345 } 9346 9347 pendingInteractions.add(interaction); 9348 }); 9349 } else { 9350 pendingInteractionMap.set(expirationTime, new Set(interactions)); 9351 9352 // Update the pending async work count for the current interactions. 9353 interactions.forEach(function (interaction) { 9354 interaction.__count++; 9355 }); 9356 } 9357 9358 var subscriber = __subscriberRef.current; 9359 if (subscriber !== null) { 9360 var threadID = computeThreadID(expirationTime, root.interactionThreadID); 9361 subscriber.onWorkScheduled(interactions, threadID); 9362 } 9363 } 9364 } 9365 } 9366 return root; 9367 } 9368 9369 9370 9371 function scheduleWork(fiber, expirationTime) { 9372 var root = scheduleWorkToRoot(fiber, expirationTime); 9373 if (root === null) { 9374 return; 9375 } 9376 9377 if (!isWorking && nextRenderExpirationTime !== NoWork && expirationTime > nextRenderExpirationTime) { 9378 // This is an interruption. (Used for performance tracking.) 9379 interruptedBy = fiber; 9380 resetStack(); 9381 } 9382 markPendingPriorityLevel(root, expirationTime); 9383 if ( 9384 // If we're in the render phase, we don't need to schedule this root 9385 // for an update, because we'll do it before we exit... 9386 !isWorking || isCommitting$1 || 9387 // ...unless this is a different root than the one we're rendering. 9388 nextRoot !== root) { 9389 var rootExpirationTime = root.expirationTime; 9390 requestWork(root, rootExpirationTime); 9391 } 9392 if (nestedUpdateCount > NESTED_UPDATE_LIMIT) { 9393 // Reset this back to zero so subsequent updates don't throw. 9394 nestedUpdateCount = 0; 9395 reactProdInvariant('185'); 9396 } 9397 } 9398 9399 function syncUpdates(fn, a, b, c, d) { 9400 return unstable_runWithPriority(unstable_ImmediatePriority, function () { 9401 return fn(a, b, c, d); 9402 }); 9403 } 9404 9405 // TODO: Everything below this is written as if it has been lifted to the 9406 // renderers. I'll do this in a follow-up. 9407 9408 // Linked-list of roots 9409 var firstScheduledRoot = null; 9410 var lastScheduledRoot = null; 9411 9412 var callbackExpirationTime = NoWork; 9413 var callbackID = void 0; 9414 var isRendering = false; 9415 var nextFlushedRoot = null; 9416 var nextFlushedExpirationTime = NoWork; 9417 var hasUnhandledError = false; 9418 var unhandledError = null; 9419 9420 var isBatchingUpdates = false; 9421 var isUnbatchingUpdates = false; 9422 9423 var completedBatches = null; 9424 9425 var originalStartTimeMs = now(); 9426 var currentRendererTime = msToExpirationTime(originalStartTimeMs); 9427 var currentSchedulerTime = currentRendererTime; 9428 9429 // Use these to prevent an infinite loop of nested updates 9430 var NESTED_UPDATE_LIMIT = 50; 9431 var nestedUpdateCount = 0; 9432 var lastCommittedRootDuringThisBatch = null; 9433 9434 function recomputeCurrentRendererTime() { 9435 var currentTimeMs = now() - originalStartTimeMs; 9436 currentRendererTime = msToExpirationTime(currentTimeMs); 9437 } 9438 9439 function scheduleCallbackWithExpirationTime(root, expirationTime) { 9440 if (callbackExpirationTime !== NoWork) { 9441 // A callback is already scheduled. Check its expiration time (timeout). 9442 if (expirationTime < callbackExpirationTime) { 9443 // Existing callback has sufficient timeout. Exit. 9444 return; 9445 } else { 9446 if (callbackID !== null) { 9447 // Existing callback has insufficient timeout. Cancel and schedule a 9448 // new one. 9449 cancelDeferredCallback$$1(callbackID); 9450 } 9451 } 9452 // The request callback timer is already running. Don't start a new one. 9453 } else { 9454 startRequestCallbackTimer(); 9455 } 9456 9457 callbackExpirationTime = expirationTime; 9458 var currentMs = now() - originalStartTimeMs; 9459 var expirationTimeMs = expirationTimeToMs(expirationTime); 9460 var timeout = expirationTimeMs - currentMs; 9461 callbackID = scheduleDeferredCallback$$1(performAsyncWork, { timeout: timeout }); 9462 } 9463 9464 // For every call to renderRoot, one of onFatal, onComplete, onSuspend, and 9465 // onYield is called upon exiting. We use these in lieu of returning a tuple. 9466 // I've also chosen not to inline them into renderRoot because these will 9467 // eventually be lifted into the renderer. 9468 function onFatal(root) { 9469 root.finishedWork = null; 9470 } 9471 9472 function onComplete(root, finishedWork, expirationTime) { 9473 root.pendingCommitExpirationTime = expirationTime; 9474 root.finishedWork = finishedWork; 9475 } 9476 9477 function onSuspend(root, finishedWork, suspendedExpirationTime, rootExpirationTime, msUntilTimeout) { 9478 root.expirationTime = rootExpirationTime; 9479 if (msUntilTimeout === 0 && !shouldYieldToRenderer()) { 9480 // Don't wait an additional tick. Commit the tree immediately. 9481 root.pendingCommitExpirationTime = suspendedExpirationTime; 9482 root.finishedWork = finishedWork; 9483 } else if (msUntilTimeout > 0) { 9484 // Wait `msUntilTimeout` milliseconds before committing. 9485 root.timeoutHandle = scheduleTimeout(onTimeout.bind(null, root, finishedWork, suspendedExpirationTime), msUntilTimeout); 9486 } 9487 } 9488 9489 function onYield(root) { 9490 root.finishedWork = null; 9491 } 9492 9493 function onTimeout(root, finishedWork, suspendedExpirationTime) { 9494 // The root timed out. Commit it. 9495 root.pendingCommitExpirationTime = suspendedExpirationTime; 9496 root.finishedWork = finishedWork; 9497 // Read the current time before entering the commit phase. We can be 9498 // certain this won't cause tearing related to batching of event updates 9499 // because we're at the top of a timer event. 9500 recomputeCurrentRendererTime(); 9501 currentSchedulerTime = currentRendererTime; 9502 flushRoot(root, suspendedExpirationTime); 9503 } 9504 9505 function onCommit(root, expirationTime) { 9506 root.expirationTime = expirationTime; 9507 root.finishedWork = null; 9508 } 9509 9510 function requestCurrentTime() { 9511 // requestCurrentTime is called by the scheduler to compute an expiration 9512 // time. 9513 // 9514 // Expiration times are computed by adding to the current time (the start 9515 // time). However, if two updates are scheduled within the same event, we 9516 // should treat their start times as simultaneous, even if the actual clock 9517 // time has advanced between the first and second call. 9518 9519 // In other words, because expiration times determine how updates are batched, 9520 // we want all updates of like priority that occur within the same event to 9521 // receive the same expiration time. Otherwise we get tearing. 9522 // 9523 // We keep track of two separate times: the current "renderer" time and the 9524 // current "scheduler" time. The renderer time can be updated whenever; it 9525 // only exists to minimize the calls performance.now. 9526 // 9527 // But the scheduler time can only be updated if there's no pending work, or 9528 // if we know for certain that we're not in the middle of an event. 9529 9530 if (isRendering) { 9531 // We're already rendering. Return the most recently read time. 9532 return currentSchedulerTime; 9533 } 9534 // Check if there's pending work. 9535 findHighestPriorityRoot(); 9536 if (nextFlushedExpirationTime === NoWork || nextFlushedExpirationTime === Never) { 9537 // If there's no pending work, or if the pending work is offscreen, we can 9538 // read the current time without risk of tearing. 9539 recomputeCurrentRendererTime(); 9540 currentSchedulerTime = currentRendererTime; 9541 return currentSchedulerTime; 9542 } 9543 // There's already pending work. We might be in the middle of a browser 9544 // event. If we were to read the current time, it could cause multiple updates 9545 // within the same event to receive different expiration times, leading to 9546 // tearing. Return the last read time. During the next idle callback, the 9547 // time will be updated. 9548 return currentSchedulerTime; 9549 } 9550 9551 // requestWork is called by the scheduler whenever a root receives an update. 9552 // It's up to the renderer to call renderRoot at some point in the future. 9553 function requestWork(root, expirationTime) { 9554 addRootToSchedule(root, expirationTime); 9555 if (isRendering) { 9556 // Prevent reentrancy. Remaining work will be scheduled at the end of 9557 // the currently rendering batch. 9558 return; 9559 } 9560 9561 if (isBatchingUpdates) { 9562 // Flush work at the end of the batch. 9563 if (isUnbatchingUpdates) { 9564 // ...unless we're inside unbatchedUpdates, in which case we should 9565 // flush it now. 9566 nextFlushedRoot = root; 9567 nextFlushedExpirationTime = Sync; 9568 performWorkOnRoot(root, Sync, false); 9569 } 9570 return; 9571 } 9572 9573 // TODO: Get rid of Sync and use current time? 9574 if (expirationTime === Sync) { 9575 performSyncWork(); 9576 } else { 9577 scheduleCallbackWithExpirationTime(root, expirationTime); 9578 } 9579 } 9580 9581 function addRootToSchedule(root, expirationTime) { 9582 // Add the root to the schedule. 9583 // Check if this root is already part of the schedule. 9584 if (root.nextScheduledRoot === null) { 9585 // This root is not already scheduled. Add it. 9586 root.expirationTime = expirationTime; 9587 if (lastScheduledRoot === null) { 9588 firstScheduledRoot = lastScheduledRoot = root; 9589 root.nextScheduledRoot = root; 9590 } else { 9591 lastScheduledRoot.nextScheduledRoot = root; 9592 lastScheduledRoot = root; 9593 lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; 9594 } 9595 } else { 9596 // This root is already scheduled, but its priority may have increased. 9597 var remainingExpirationTime = root.expirationTime; 9598 if (expirationTime > remainingExpirationTime) { 9599 // Update the priority. 9600 root.expirationTime = expirationTime; 9601 } 9602 } 9603 } 9604 9605 function findHighestPriorityRoot() { 9606 var highestPriorityWork = NoWork; 9607 var highestPriorityRoot = null; 9608 if (lastScheduledRoot !== null) { 9609 var previousScheduledRoot = lastScheduledRoot; 9610 var root = firstScheduledRoot; 9611 while (root !== null) { 9612 var remainingExpirationTime = root.expirationTime; 9613 if (remainingExpirationTime === NoWork) { 9614 // This root no longer has work. Remove it from the scheduler. 9615 9616 // TODO: This check is redudant, but Flow is confused by the branch 9617 // below where we set lastScheduledRoot to null, even though we break 9618 // from the loop right after. 9619 !(previousScheduledRoot !== null && lastScheduledRoot !== null) ? reactProdInvariant('244') : void 0; 9620 if (root === root.nextScheduledRoot) { 9621 // This is the only root in the list. 9622 root.nextScheduledRoot = null; 9623 firstScheduledRoot = lastScheduledRoot = null; 9624 break; 9625 } else if (root === firstScheduledRoot) { 9626 // This is the first root in the list. 9627 var next = root.nextScheduledRoot; 9628 firstScheduledRoot = next; 9629 lastScheduledRoot.nextScheduledRoot = next; 9630 root.nextScheduledRoot = null; 9631 } else if (root === lastScheduledRoot) { 9632 // This is the last root in the list. 9633 lastScheduledRoot = previousScheduledRoot; 9634 lastScheduledRoot.nextScheduledRoot = firstScheduledRoot; 9635 root.nextScheduledRoot = null; 9636 break; 9637 } else { 9638 previousScheduledRoot.nextScheduledRoot = root.nextScheduledRoot; 9639 root.nextScheduledRoot = null; 9640 } 9641 root = previousScheduledRoot.nextScheduledRoot; 9642 } else { 9643 if (remainingExpirationTime > highestPriorityWork) { 9644 // Update the priority, if it's higher 9645 highestPriorityWork = remainingExpirationTime; 9646 highestPriorityRoot = root; 9647 } 9648 if (root === lastScheduledRoot) { 9649 break; 9650 } 9651 if (highestPriorityWork === Sync) { 9652 // Sync is highest priority by definition so 9653 // we can stop searching. 9654 break; 9655 } 9656 previousScheduledRoot = root; 9657 root = root.nextScheduledRoot; 9658 } 9659 } 9660 } 9661 9662 nextFlushedRoot = highestPriorityRoot; 9663 nextFlushedExpirationTime = highestPriorityWork; 9664 } 9665 9666 // TODO: This wrapper exists because many of the older tests (the ones that use 9667 // flushDeferredPri) rely on the number of times `shouldYield` is called. We 9668 // should get rid of it. 9669 var didYield = false; 9670 function shouldYieldToRenderer() { 9671 if (didYield) { 9672 return true; 9673 } 9674 if (shouldYield$$1()) { 9675 didYield = true; 9676 return true; 9677 } 9678 return false; 9679 } 9680 9681 function performAsyncWork() { 9682 try { 9683 if (!shouldYieldToRenderer()) { 9684 // The callback timed out. That means at least one update has expired. 9685 // Iterate through the root schedule. If they contain expired work, set 9686 // the next render expiration time to the current time. This has the effect 9687 // of flushing all expired work in a single batch, instead of flushing each 9688 // level one at a time. 9689 if (firstScheduledRoot !== null) { 9690 recomputeCurrentRendererTime(); 9691 var root = firstScheduledRoot; 9692 do { 9693 didExpireAtExpirationTime(root, currentRendererTime); 9694 // The root schedule is circular, so this is never null. 9695 root = root.nextScheduledRoot; 9696 } while (root !== firstScheduledRoot); 9697 } 9698 } 9699 performWork(NoWork, true); 9700 } finally { 9701 didYield = false; 9702 } 9703 } 9704 9705 function performSyncWork() { 9706 performWork(Sync, false); 9707 } 9708 9709 function performWork(minExpirationTime, isYieldy) { 9710 // Keep working on roots until there's no more work, or until there's a higher 9711 // priority event. 9712 findHighestPriorityRoot(); 9713 9714 if (isYieldy) { 9715 recomputeCurrentRendererTime(); 9716 currentSchedulerTime = currentRendererTime; 9717 9718 if (enableUserTimingAPI) { 9719 var didExpire = nextFlushedExpirationTime > currentRendererTime; 9720 var timeout = expirationTimeToMs(nextFlushedExpirationTime); 9721 stopRequestCallbackTimer(didExpire, timeout); 9722 } 9723 9724 while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime && !(didYield && currentRendererTime > nextFlushedExpirationTime)) { 9725 performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, currentRendererTime > nextFlushedExpirationTime); 9726 findHighestPriorityRoot(); 9727 recomputeCurrentRendererTime(); 9728 currentSchedulerTime = currentRendererTime; 9729 } 9730 } else { 9731 while (nextFlushedRoot !== null && nextFlushedExpirationTime !== NoWork && minExpirationTime <= nextFlushedExpirationTime) { 9732 performWorkOnRoot(nextFlushedRoot, nextFlushedExpirationTime, false); 9733 findHighestPriorityRoot(); 9734 } 9735 } 9736 9737 // We're done flushing work. Either we ran out of time in this callback, 9738 // or there's no more work left with sufficient priority. 9739 9740 // If we're inside a callback, set this to false since we just completed it. 9741 if (isYieldy) { 9742 callbackExpirationTime = NoWork; 9743 callbackID = null; 9744 } 9745 // If there's work left over, schedule a new callback. 9746 if (nextFlushedExpirationTime !== NoWork) { 9747 scheduleCallbackWithExpirationTime(nextFlushedRoot, nextFlushedExpirationTime); 9748 } 9749 9750 // Clean-up. 9751 finishRendering(); 9752 } 9753 9754 function flushRoot(root, expirationTime) { 9755 !!isRendering ? reactProdInvariant('253') : void 0; 9756 // Perform work on root as if the given expiration time is the current time. 9757 // This has the effect of synchronously flushing all work up to and 9758 // including the given time. 9759 nextFlushedRoot = root; 9760 nextFlushedExpirationTime = expirationTime; 9761 performWorkOnRoot(root, expirationTime, false); 9762 // Flush any sync work that was scheduled by lifecycles 9763 performSyncWork(); 9764 } 9765 9766 function finishRendering() { 9767 nestedUpdateCount = 0; 9768 lastCommittedRootDuringThisBatch = null; 9769 9770 if (completedBatches !== null) { 9771 var batches = completedBatches; 9772 completedBatches = null; 9773 for (var i = 0; i < batches.length; i++) { 9774 var batch = batches[i]; 9775 try { 9776 batch._onComplete(); 9777 } catch (error) { 9778 if (!hasUnhandledError) { 9779 hasUnhandledError = true; 9780 unhandledError = error; 9781 } 9782 } 9783 } 9784 } 9785 9786 if (hasUnhandledError) { 9787 var error = unhandledError; 9788 unhandledError = null; 9789 hasUnhandledError = false; 9790 throw error; 9791 } 9792 } 9793 9794 function performWorkOnRoot(root, expirationTime, isYieldy) { 9795 !!isRendering ? reactProdInvariant('245') : void 0; 9796 9797 isRendering = true; 9798 9799 // Check if this is async work or sync/expired work. 9800 if (!isYieldy) { 9801 // Flush work without yielding. 9802 // TODO: Non-yieldy work does not necessarily imply expired work. A renderer 9803 // may want to perform some work without yielding, but also without 9804 // requiring the root to complete (by triggering placeholders). 9805 9806 var finishedWork = root.finishedWork; 9807 if (finishedWork !== null) { 9808 // This root is already complete. We can commit it. 9809 completeRoot(root, finishedWork, expirationTime); 9810 } else { 9811 root.finishedWork = null; 9812 // If this root previously suspended, clear its existing timeout, since 9813 // we're about to try rendering again. 9814 var timeoutHandle = root.timeoutHandle; 9815 if (timeoutHandle !== noTimeout) { 9816 root.timeoutHandle = noTimeout; 9817 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above 9818 cancelTimeout(timeoutHandle); 9819 } 9820 renderRoot(root, isYieldy); 9821 finishedWork = root.finishedWork; 9822 if (finishedWork !== null) { 9823 // We've completed the root. Commit it. 9824 completeRoot(root, finishedWork, expirationTime); 9825 } 9826 } 9827 } else { 9828 // Flush async work. 9829 var _finishedWork = root.finishedWork; 9830 if (_finishedWork !== null) { 9831 // This root is already complete. We can commit it. 9832 completeRoot(root, _finishedWork, expirationTime); 9833 } else { 9834 root.finishedWork = null; 9835 // If this root previously suspended, clear its existing timeout, since 9836 // we're about to try rendering again. 9837 var _timeoutHandle = root.timeoutHandle; 9838 if (_timeoutHandle !== noTimeout) { 9839 root.timeoutHandle = noTimeout; 9840 // $FlowFixMe Complains noTimeout is not a TimeoutID, despite the check above 9841 cancelTimeout(_timeoutHandle); 9842 } 9843 renderRoot(root, isYieldy); 9844 _finishedWork = root.finishedWork; 9845 if (_finishedWork !== null) { 9846 // We've completed the root. Check the if we should yield one more time 9847 // before committing. 9848 if (!shouldYieldToRenderer()) { 9849 // Still time left. Commit the root. 9850 completeRoot(root, _finishedWork, expirationTime); 9851 } else { 9852 // There's no time left. Mark this root as complete. We'll come 9853 // back and commit it later. 9854 root.finishedWork = _finishedWork; 9855 } 9856 } 9857 } 9858 } 9859 9860 isRendering = false; 9861 } 9862 9863 function completeRoot(root, finishedWork, expirationTime) { 9864 // Check if there's a batch that matches this expiration time. 9865 var firstBatch = root.firstBatch; 9866 if (firstBatch !== null && firstBatch._expirationTime >= expirationTime) { 9867 if (completedBatches === null) { 9868 completedBatches = [firstBatch]; 9869 } else { 9870 completedBatches.push(firstBatch); 9871 } 9872 if (firstBatch._defer) { 9873 // This root is blocked from committing by a batch. Unschedule it until 9874 // we receive another update. 9875 root.finishedWork = finishedWork; 9876 root.expirationTime = NoWork; 9877 return; 9878 } 9879 } 9880 9881 // Commit the root. 9882 root.finishedWork = null; 9883 9884 // Check if this is a nested update (a sync update scheduled during the 9885 // commit phase). 9886 if (root === lastCommittedRootDuringThisBatch) { 9887 // If the next root is the same as the previous root, this is a nested 9888 // update. To prevent an infinite loop, increment the nested update count. 9889 nestedUpdateCount++; 9890 } else { 9891 // Reset whenever we switch roots. 9892 lastCommittedRootDuringThisBatch = root; 9893 nestedUpdateCount = 0; 9894 } 9895 unstable_runWithPriority(unstable_ImmediatePriority, function () { 9896 commitRoot(root, finishedWork); 9897 }); 9898 } 9899 9900 function onUncaughtError(error) { 9901 !(nextFlushedRoot !== null) ? reactProdInvariant('246') : void 0; 9902 // Unschedule this root so we don't work on it again until there's 9903 // another update. 9904 nextFlushedRoot.expirationTime = NoWork; 9905 if (!hasUnhandledError) { 9906 hasUnhandledError = true; 9907 unhandledError = error; 9908 } 9909 } 9910 9911 // TODO: Batching should be implemented at the renderer level, not inside 9912 // the reconciler. 9913 function batchedUpdates(fn, a) { 9914 var previousIsBatchingUpdates = isBatchingUpdates; 9915 isBatchingUpdates = true; 9916 try { 9917 return fn(a); 9918 } finally { 9919 isBatchingUpdates = previousIsBatchingUpdates; 9920 if (!isBatchingUpdates && !isRendering) { 9921 performSyncWork(); 9922 } 9923 } 9924 } 9925 9926 // TODO: Batching should be implemented at the renderer level, not within 9927 // the reconciler. 9928 function flushSync(fn, a) { 9929 !!isRendering ? reactProdInvariant('187') : void 0; 9930 var previousIsBatchingUpdates = isBatchingUpdates; 9931 isBatchingUpdates = true; 9932 try { 9933 return syncUpdates(fn, a); 9934 } finally { 9935 isBatchingUpdates = previousIsBatchingUpdates; 9936 performSyncWork(); 9937 } 9938 } 9939 9940 function getContextForSubtree(parentComponent) { 9941 if (!parentComponent) { 9942 return emptyContextObject; 9943 } 9944 9945 var fiber = get(parentComponent); 9946 var parentContext = findCurrentUnmaskedContext(fiber); 9947 9948 if (fiber.tag === ClassComponent) { 9949 var Component = fiber.type; 9950 if (isContextProvider(Component)) { 9951 return processChildContext(fiber, Component, parentContext); 9952 } 9953 } 9954 9955 return parentContext; 9956 } 9957 9958 function scheduleRootUpdate(current$$1, element, expirationTime, callback) { 9959 var update = createUpdate(expirationTime); 9960 // Caution: React DevTools currently depends on this property 9961 // being called "element". 9962 update.payload = { element: element }; 9963 9964 callback = callback === undefined ? null : callback; 9965 if (callback !== null) { 9966 update.callback = callback; 9967 } 9968 9969 flushPassiveEffects$1(); 9970 enqueueUpdate(current$$1, update); 9971 scheduleWork(current$$1, expirationTime); 9972 9973 return expirationTime; 9974 } 9975 9976 function updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback) { 9977 // TODO: If this is a nested container, this won't be the root. 9978 var current$$1 = container.current; 9979 9980 var context = getContextForSubtree(parentComponent); 9981 if (container.context === null) { 9982 container.context = context; 9983 } else { 9984 container.pendingContext = context; 9985 } 9986 9987 return scheduleRootUpdate(current$$1, element, expirationTime, callback); 9988 } 9989 9990 function createContainer(containerInfo, isConcurrent, hydrate) { 9991 return createFiberRoot(containerInfo, isConcurrent, hydrate); 9992 } 9993 9994 function updateContainer(element, container, parentComponent, callback) { 9995 var current$$1 = container.current; 9996 var currentTime = requestCurrentTime(); 9997 var expirationTime = computeExpirationForFiber(currentTime, current$$1); 9998 return updateContainerAtExpirationTime(element, container, parentComponent, expirationTime, callback); 9999 } 10000 10001 function getPublicRootInstance(container) { 10002 var containerFiber = container.current; 10003 if (!containerFiber.child) { 10004 return null; 10005 } 10006 switch (containerFiber.child.tag) { 10007 case HostComponent: 10008 return getPublicInstance(containerFiber.child.stateNode); 10009 default: 10010 return containerFiber.child.stateNode; 10011 } 10012 } 10013 10014 10015 10016 var overrideProps = null; 10017 10018 function injectIntoDevTools(devToolsConfig) { 10019 var findFiberByHostInstance = devToolsConfig.findFiberByHostInstance; 10020 var ReactCurrentDispatcher = ReactSharedInternals.ReactCurrentDispatcher; 10021 10022 10023 return injectInternals(_assign({}, devToolsConfig, { 10024 overrideProps: overrideProps, 10025 currentDispatcherRef: ReactCurrentDispatcher, 10026 findHostInstanceByFiber: function (fiber) { 10027 var hostFiber = findCurrentHostFiber(fiber); 10028 if (hostFiber === null) { 10029 return null; 10030 } 10031 return hostFiber.stateNode; 10032 }, 10033 findFiberByHostInstance: function (instance) { 10034 if (!findFiberByHostInstance) { 10035 // Might not be implemented by the renderer. 10036 return null; 10037 } 10038 return findFiberByHostInstance(instance); 10039 } 10040 })); 10041 } 10042 10043 // This file intentionally does *not* have the Flow annotation. 10044 // Don't add it. See `./inline-typed.js` for an explanation. 10045 10046 // TODO: this is special because it gets imported during build. 10047 10048 var ReactVersion = '16.8.6'; 10049 10050 var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 10051 10052 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 10053 10054 function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } 10055 10056 // for .act's return value 10057 10058 10059 var defaultTestOptions = { 10060 createNodeMock: function () { 10061 return null; 10062 } 10063 }; 10064 10065 function toJSON(inst) { 10066 if (inst.isHidden) { 10067 // Omit timed out children from output entirely. This seems like the least 10068 // surprising behavior. We could perhaps add a separate API that includes 10069 // them, if it turns out people need it. 10070 return null; 10071 } 10072 switch (inst.tag) { 10073 case 'TEXT': 10074 return inst.text; 10075 case 'INSTANCE': 10076 { 10077 /* eslint-disable no-unused-vars */ 10078 // We don't include the `children` prop in JSON. 10079 // Instead, we will include the actual rendered children. 10080 var _inst$props = inst.props, 10081 _children = _inst$props.children, 10082 _props = _objectWithoutProperties(_inst$props, ['children']); 10083 /* eslint-enable */ 10084 10085 10086 var renderedChildren = null; 10087 if (inst.children && inst.children.length) { 10088 for (var i = 0; i < inst.children.length; i++) { 10089 var renderedChild = toJSON(inst.children[i]); 10090 if (renderedChild !== null) { 10091 if (renderedChildren === null) { 10092 renderedChildren = [renderedChild]; 10093 } else { 10094 renderedChildren.push(renderedChild); 10095 } 10096 } 10097 } 10098 } 10099 var json = { 10100 type: inst.type, 10101 props: _props, 10102 children: renderedChildren 10103 }; 10104 Object.defineProperty(json, '$$typeof', { 10105 value: Symbol.for('react.test.json') 10106 }); 10107 return json; 10108 } 10109 default: 10110 throw new Error('Unexpected node type in toJSON: ' + inst.tag); 10111 } 10112 } 10113 10114 function childrenToTree(node) { 10115 if (!node) { 10116 return null; 10117 } 10118 var children = nodeAndSiblingsArray(node); 10119 if (children.length === 0) { 10120 return null; 10121 } else if (children.length === 1) { 10122 return toTree(children[0]); 10123 } 10124 return flatten(children.map(toTree)); 10125 } 10126 10127 function nodeAndSiblingsArray(nodeWithSibling) { 10128 var array = []; 10129 var node = nodeWithSibling; 10130 while (node != null) { 10131 array.push(node); 10132 node = node.sibling; 10133 } 10134 return array; 10135 } 10136 10137 function flatten(arr) { 10138 var result = []; 10139 var stack = [{ i: 0, array: arr }]; 10140 while (stack.length) { 10141 var n = stack.pop(); 10142 while (n.i < n.array.length) { 10143 var el = n.array[n.i]; 10144 n.i += 1; 10145 if (Array.isArray(el)) { 10146 stack.push(n); 10147 stack.push({ i: 0, array: el }); 10148 break; 10149 } 10150 result.push(el); 10151 } 10152 } 10153 return result; 10154 } 10155 10156 function toTree(node) { 10157 if (node == null) { 10158 return null; 10159 } 10160 switch (node.tag) { 10161 case HostRoot: 10162 return childrenToTree(node.child); 10163 case HostPortal: 10164 return childrenToTree(node.child); 10165 case ClassComponent: 10166 return { 10167 nodeType: 'component', 10168 type: node.type, 10169 props: _assign({}, node.memoizedProps), 10170 instance: node.stateNode, 10171 rendered: childrenToTree(node.child) 10172 }; 10173 case FunctionComponent: 10174 case SimpleMemoComponent: 10175 return { 10176 nodeType: 'component', 10177 type: node.type, 10178 props: _assign({}, node.memoizedProps), 10179 instance: null, 10180 rendered: childrenToTree(node.child) 10181 }; 10182 case HostComponent: 10183 { 10184 return { 10185 nodeType: 'host', 10186 type: node.type, 10187 props: _assign({}, node.memoizedProps), 10188 instance: null, // TODO: use createNodeMock here somehow? 10189 rendered: flatten(nodeAndSiblingsArray(node.child).map(toTree)) 10190 }; 10191 } 10192 case HostText: 10193 return node.stateNode.text; 10194 case Fragment: 10195 case ContextProvider: 10196 case ContextConsumer: 10197 case Mode: 10198 case Profiler: 10199 case ForwardRef: 10200 case MemoComponent: 10201 case IncompleteClassComponent: 10202 return childrenToTree(node.child); 10203 default: 10204 reactProdInvariant('214', node.tag); 10205 } 10206 } 10207 10208 var validWrapperTypes = new Set([FunctionComponent, ClassComponent, HostComponent, ForwardRef, MemoComponent, SimpleMemoComponent, 10209 // Normally skipped, but used when there's more than one root child. 10210 HostRoot]); 10211 10212 function getChildren(parent) { 10213 var children = []; 10214 var startingNode = parent; 10215 var node = startingNode; 10216 if (node.child === null) { 10217 return children; 10218 } 10219 node.child.return = node; 10220 node = node.child; 10221 outer: while (true) { 10222 var descend = false; 10223 if (validWrapperTypes.has(node.tag)) { 10224 children.push(wrapFiber(node)); 10225 } else if (node.tag === HostText) { 10226 children.push('' + node.memoizedProps); 10227 } else { 10228 descend = true; 10229 } 10230 if (descend && node.child !== null) { 10231 node.child.return = node; 10232 node = node.child; 10233 continue; 10234 } 10235 while (node.sibling === null) { 10236 if (node.return === startingNode) { 10237 break outer; 10238 } 10239 node = node.return; 10240 } 10241 node.sibling.return = node.return; 10242 node = node.sibling; 10243 } 10244 return children; 10245 } 10246 10247 var ReactTestInstance = function () { 10248 ReactTestInstance.prototype._currentFiber = function _currentFiber() { 10249 // Throws if this component has been unmounted. 10250 var fiber = findCurrentFiberUsingSlowPath(this._fiber); 10251 !(fiber !== null) ? reactProdInvariant('224') : void 0; 10252 return fiber; 10253 }; 10254 10255 function ReactTestInstance(fiber) { 10256 _classCallCheck(this, ReactTestInstance); 10257 10258 !validWrapperTypes.has(fiber.tag) ? reactProdInvariant('225', fiber.tag) : void 0; 10259 this._fiber = fiber; 10260 } 10261 10262 // Custom search functions 10263 ReactTestInstance.prototype.find = function find(predicate) { 10264 return expectOne(this.findAll(predicate, { deep: false }), 'matching custom predicate: ' + predicate.toString()); 10265 }; 10266 10267 ReactTestInstance.prototype.findByType = function findByType(type) { 10268 return expectOne(this.findAllByType(type, { deep: false }), 'with node type: "' + (type.displayName || type.name) + '"'); 10269 }; 10270 10271 ReactTestInstance.prototype.findByProps = function findByProps(props) { 10272 return expectOne(this.findAllByProps(props, { deep: false }), 'with props: ' + JSON.stringify(props)); 10273 }; 10274 10275 ReactTestInstance.prototype.findAll = function findAll(predicate) { 10276 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; 10277 10278 return _findAll(this, predicate, options); 10279 }; 10280 10281 ReactTestInstance.prototype.findAllByType = function findAllByType(type) { 10282 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; 10283 10284 return _findAll(this, function (node) { 10285 return node.type === type; 10286 }, options); 10287 }; 10288 10289 ReactTestInstance.prototype.findAllByProps = function findAllByProps(props) { 10290 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; 10291 10292 return _findAll(this, function (node) { 10293 return node.props && propsMatch(node.props, props); 10294 }, options); 10295 }; 10296 10297 _createClass(ReactTestInstance, [{ 10298 key: 'instance', 10299 get: function () { 10300 if (this._fiber.tag === HostComponent) { 10301 return getPublicInstance(this._fiber.stateNode); 10302 } else { 10303 return this._fiber.stateNode; 10304 } 10305 } 10306 }, { 10307 key: 'type', 10308 get: function () { 10309 return this._fiber.type; 10310 } 10311 }, { 10312 key: 'props', 10313 get: function () { 10314 return this._currentFiber().memoizedProps; 10315 } 10316 }, { 10317 key: 'parent', 10318 get: function () { 10319 var parent = this._fiber.return; 10320 while (parent !== null) { 10321 if (validWrapperTypes.has(parent.tag)) { 10322 if (parent.tag === HostRoot) { 10323 // Special case: we only "materialize" instances for roots 10324 // if they have more than a single child. So we'll check that now. 10325 if (getChildren(parent).length < 2) { 10326 return null; 10327 } 10328 } 10329 return wrapFiber(parent); 10330 } 10331 parent = parent.return; 10332 } 10333 return null; 10334 } 10335 }, { 10336 key: 'children', 10337 get: function () { 10338 return getChildren(this._currentFiber()); 10339 } 10340 }]); 10341 10342 return ReactTestInstance; 10343 }(); 10344 10345 function _findAll(root, predicate, options) { 10346 var deep = options ? options.deep : true; 10347 var results = []; 10348 10349 if (predicate(root)) { 10350 results.push(root); 10351 if (!deep) { 10352 return results; 10353 } 10354 } 10355 10356 root.children.forEach(function (child) { 10357 if (typeof child === 'string') { 10358 return; 10359 } 10360 results.push.apply(results, _findAll(child, predicate, options)); 10361 }); 10362 10363 return results; 10364 } 10365 10366 function expectOne(all, message) { 10367 if (all.length === 1) { 10368 return all[0]; 10369 } 10370 10371 var prefix = all.length === 0 ? 'No instances found ' : 'Expected 1 but found ' + all.length + ' instances '; 10372 10373 throw new Error(prefix + message); 10374 } 10375 10376 function propsMatch(props, filter) { 10377 for (var key in filter) { 10378 if (props[key] !== filter[key]) { 10379 return false; 10380 } 10381 } 10382 return true; 10383 } 10384 10385 var ReactTestRendererFiber = { 10386 create: function (element, options) { 10387 var createNodeMock = defaultTestOptions.createNodeMock; 10388 var isConcurrent = false; 10389 if (typeof options === 'object' && options !== null) { 10390 if (typeof options.createNodeMock === 'function') { 10391 createNodeMock = options.createNodeMock; 10392 } 10393 if (options.unstable_isConcurrent === true) { 10394 isConcurrent = true; 10395 } 10396 } 10397 var container = { 10398 children: [], 10399 createNodeMock: createNodeMock, 10400 tag: 'CONTAINER' 10401 }; 10402 var root = createContainer(container, isConcurrent, false); 10403 !(root != null) ? reactProdInvariant('215') : void 0; 10404 updateContainer(element, root, null, null); 10405 10406 var entry = { 10407 root: undefined, // makes flow happy 10408 // we define a 'getter' for 'root' below using 'Object.defineProperty' 10409 toJSON: function () { 10410 if (root == null || root.current == null || container == null) { 10411 return null; 10412 } 10413 if (container.children.length === 0) { 10414 return null; 10415 } 10416 if (container.children.length === 1) { 10417 return toJSON(container.children[0]); 10418 } 10419 if (container.children.length === 2 && container.children[0].isHidden === true && container.children[1].isHidden === false) { 10420 // Omit timed out children from output entirely, including the fact that we 10421 // temporarily wrap fallback and timed out children in an array. 10422 return toJSON(container.children[1]); 10423 } 10424 var renderedChildren = null; 10425 if (container.children && container.children.length) { 10426 for (var i = 0; i < container.children.length; i++) { 10427 var renderedChild = toJSON(container.children[i]); 10428 if (renderedChild !== null) { 10429 if (renderedChildren === null) { 10430 renderedChildren = [renderedChild]; 10431 } else { 10432 renderedChildren.push(renderedChild); 10433 } 10434 } 10435 } 10436 } 10437 return renderedChildren; 10438 }, 10439 toTree: function () { 10440 if (root == null || root.current == null) { 10441 return null; 10442 } 10443 return toTree(root.current); 10444 }, 10445 update: function (newElement) { 10446 if (root == null || root.current == null) { 10447 return; 10448 } 10449 updateContainer(newElement, root, null, null); 10450 }, 10451 unmount: function () { 10452 if (root == null || root.current == null) { 10453 return; 10454 } 10455 updateContainer(null, root, null, null); 10456 container = null; 10457 root = null; 10458 }, 10459 getInstance: function () { 10460 if (root == null || root.current == null) { 10461 return null; 10462 } 10463 return getPublicRootInstance(root); 10464 }, 10465 10466 10467 unstable_flushAll: flushAll, 10468 unstable_flushSync: function (fn) { 10469 clearYields(); 10470 return flushSync(fn); 10471 }, 10472 10473 unstable_flushNumberOfYields: flushNumberOfYields, 10474 unstable_clearYields: clearYields 10475 }; 10476 10477 Object.defineProperty(entry, 'root', { 10478 configurable: true, 10479 enumerable: true, 10480 get: function () { 10481 if (root === null) { 10482 throw new Error("Can't access .root on unmounted test renderer"); 10483 } 10484 var children = getChildren(root.current); 10485 if (children.length === 0) { 10486 throw new Error("Can't access .root on unmounted test renderer"); 10487 } else if (children.length === 1) { 10488 // Normally, we skip the root and just give you the child. 10489 return children[0]; 10490 } else { 10491 // However, we give you the root if there's more than one root child. 10492 // We could make this the behavior for all cases but it would be a breaking change. 10493 return wrapFiber(root.current); 10494 } 10495 } 10496 }); 10497 10498 return entry; 10499 }, 10500 10501 10502 unstable_yield: yieldValue, 10503 unstable_clearYields: clearYields, 10504 10505 /* eslint-disable camelcase */ 10506 unstable_batchedUpdates: batchedUpdates, 10507 /* eslint-enable camelcase */ 10508 10509 unstable_setNowImplementation: setNowImplementation, 10510 10511 act: function (callback) { 10512 // note: keep these warning messages in sync with 10513 // createNoop.js and ReactTestUtils.js 10514 var result = batchedUpdates(callback); 10515 flushPassiveEffects(); 10516 // we want the user to not expect a return, 10517 // but we want to warn if they use it like they can await on it. 10518 return { 10519 then: function () { 10520 10521 } 10522 }; 10523 } 10524 }; 10525 10526 // root used to flush effects during .act() calls 10527 var actRoot = createContainer({ 10528 children: [], 10529 createNodeMock: defaultTestOptions.createNodeMock, 10530 tag: 'CONTAINER' 10531 }, true, false); 10532 10533 function flushPassiveEffects() { 10534 // Trick to flush passive effects without exposing an internal API: 10535 // Create a throwaway root and schedule a dummy update on it. 10536 updateContainer(null, actRoot, null, null); 10537 } 10538 10539 var fiberToWrapper = new WeakMap(); 10540 function wrapFiber(fiber) { 10541 var wrapper = fiberToWrapper.get(fiber); 10542 if (wrapper === undefined && fiber.alternate !== null) { 10543 wrapper = fiberToWrapper.get(fiber.alternate); 10544 } 10545 if (wrapper === undefined) { 10546 wrapper = new ReactTestInstance(fiber); 10547 fiberToWrapper.set(fiber, wrapper); 10548 } 10549 return wrapper; 10550 } 10551 10552 // Enable ReactTestRenderer to be used to test DevTools integration. 10553 injectIntoDevTools({ 10554 findFiberByHostInstance: function () { 10555 throw new Error('TestRenderer does not support findFiberByHostInstance()'); 10556 }, 10557 bundleType: 0, 10558 version: ReactVersion, 10559 rendererPackageName: 'react-test-renderer' 10560 }); 10561 10562 10563 10564 var ReactTestRenderer = ({ 10565 default: ReactTestRendererFiber 10566 }); 10567 10568 var ReactTestRenderer$1 = ( ReactTestRenderer && ReactTestRendererFiber ) || ReactTestRenderer; 10569 10570 // TODO: decide on the top-level export form. 10571 // This is hacky but makes it work with both Rollup and Jest. 10572 var reactTestRenderer = ReactTestRenderer$1.default || ReactTestRenderer$1; 10573 10574 export default reactTestRenderer;