Use strict equality (===) to prevent type coercion bugs
(current.mode & ProfileMode) !== NoMode
1/**2 * Copyright (c) Meta Platforms, Inc. and affiliates.3 *4 * This source code is licensed under the MIT license found in the5 * LICENSE file in the root directory of this source tree.6 *7 * @flow8 */910import type {11 ViewTransitionProps,12 ProfilerProps,13 ProfilerPhase,14} from 'shared/ReactTypes';15import type {Fiber} from './ReactInternalTypes';16import type {UpdateQueue} from './ReactFiberClassUpdateQueue';17import type {FunctionComponentUpdateQueue} from './ReactFiberHooks';18import type {HookFlags} from './ReactHookEffectTags';19import type {FragmentInstanceType} from './ReactFiberConfig';20import type {ViewTransitionState} from './ReactFiberViewTransitionComponent';2122import {getViewTransitionName} from './ReactFiberViewTransitionComponent';2324import {25 enableProfilerTimer,26 enableProfilerCommitHooks,27 enableProfilerNestedUpdatePhase,28 enableSchedulingProfiler,29 enableViewTransition,30 enableFragmentRefs,31} from 'shared/ReactFeatureFlags';32import {33 ClassComponent,34 Fragment,35 HostComponent,36 HostHoistable,37 HostSingleton,38 ViewTransitionComponent,39} from './ReactWorkTags';40import {NoFlags} from './ReactFiberFlags';41import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';42import {resolveClassComponentProps} from './ReactFiberClassComponent';43import {44 recordEffectDuration,45 startEffectTimer,46 isCurrentUpdateNested,47} from './ReactProfilerTimer';48import {NoMode, ProfileMode} from './ReactTypeOfMode';49import {50 commitCallbacks,51 commitHiddenCallbacks,52} from './ReactFiberClassUpdateQueue';53import {54 getPublicInstance,55 createViewTransitionInstance,56 createFragmentInstance,57} from './ReactFiberConfig';58import {59 captureCommitPhaseError,60 setIsRunningInsertionEffect,61} from './ReactFiberWorkLoop';62import {63 NoFlags as NoHookEffect,64 Layout as HookLayout,65 Insertion as HookInsertion,66 Passive as HookPassive,67} from './ReactHookEffectTags';68import {didWarnAboutReassigningProps} from './ReactFiberBeginWork';69import {70 markComponentPassiveEffectMountStarted,71 markComponentPassiveEffectMountStopped,72 markComponentPassiveEffectUnmountStarted,73 markComponentPassiveEffectUnmountStopped,74 markComponentLayoutEffectMountStarted,75 markComponentLayoutEffectMountStopped,76 markComponentLayoutEffectUnmountStarted,77 markComponentLayoutEffectUnmountStopped,78} from './ReactFiberDevToolsHook';79import {80 callComponentDidMountInDEV,81 callComponentDidUpdateInDEV,82 callComponentWillUnmountInDEV,83 callCreateInDEV,84 callDestroyInDEV,85} from './ReactFiberCallUserSpace';8687import {runWithFiberInDEV} from './ReactCurrentFiber';8889function shouldProfile(current: Fiber): boolean {90 return (91 enableProfilerTimer &&92 enableProfilerCommitHooks &&93 (current.mode & ProfileMode) !== NoMode94 );95}9697export function commitHookLayoutEffects(98 finishedWork: Fiber,99 hookFlags: HookFlags,100) {101 // At this point layout effects have already been destroyed (during mutation phase).102 // This is done to prevent sibling component effects from interfering with each other,103 // e.g. a destroy function in one component should never override a ref set104 // by a create function in another component during the same commit.105 if (shouldProfile(finishedWork)) {106 startEffectTimer();107 commitHookEffectListMount(hookFlags, finishedWork);108 recordEffectDuration(finishedWork);109 } else {110 commitHookEffectListMount(hookFlags, finishedWork);111 }112}113114export function commitHookLayoutUnmountEffects(115 finishedWork: Fiber,116 nearestMountedAncestor: null | Fiber,117 hookFlags: HookFlags,118) {119 // Layout effects are destroyed during the mutation phase so that all120 // destroy functions for all fibers are called before any create functions.121 // This prevents sibling component effects from interfering with each other,122 // e.g. a destroy function in one component should never override a ref set123 // by a create function in another component during the same commit.124 if (shouldProfile(finishedWork)) {125 startEffectTimer();126 commitHookEffectListUnmount(127 hookFlags,128 finishedWork,129 nearestMountedAncestor,130 );131 recordEffectDuration(finishedWork);132 } else {133 commitHookEffectListUnmount(134 hookFlags,135 finishedWork,136 nearestMountedAncestor,137 );138 }139}140141export function commitHookEffectListMount(142 flags: HookFlags,143 finishedWork: Fiber,144) {145 try {146 const updateQueue: FunctionComponentUpdateQueue | null =147 finishedWork.updateQueue as any;148 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;149 if (lastEffect !== null) {150 const firstEffect = lastEffect.next;151 let effect = firstEffect;152 do {153 if ((effect.tag & flags) === flags) {154 if (enableSchedulingProfiler) {155 if ((flags & HookPassive) !== NoHookEffect) {156 markComponentPassiveEffectMountStarted(finishedWork);157 } else if ((flags & HookLayout) !== NoHookEffect) {158 markComponentLayoutEffectMountStarted(finishedWork);159 }160 }161162 // Mount163 let destroy;164 if (__DEV__) {165 if ((flags & HookInsertion) !== NoHookEffect) {166 setIsRunningInsertionEffect(true);167 }168 destroy = runWithFiberInDEV(finishedWork, callCreateInDEV, effect);169 if ((flags & HookInsertion) !== NoHookEffect) {170 setIsRunningInsertionEffect(false);171 }172 } else {173 const create = effect.create;174 const inst = effect.inst;175 destroy = create();176 inst.destroy = destroy;177 }178179 if (enableSchedulingProfiler) {180 if ((flags & HookPassive) !== NoHookEffect) {181 markComponentPassiveEffectMountStopped();182 } else if ((flags & HookLayout) !== NoHookEffect) {183 markComponentLayoutEffectMountStopped();184 }185 }186187 if (__DEV__) {188 if (destroy !== undefined && typeof destroy !== 'function') {189 let hookName;190 if ((effect.tag & HookLayout) !== NoFlags) {191 hookName = 'useLayoutEffect';192 } else if ((effect.tag & HookInsertion) !== NoFlags) {193 hookName = 'useInsertionEffect';194 } else {195 hookName = 'useEffect';196 }197 let addendum;198 // $FlowFixMe[invalid-compare]199 if (destroy === null) {200 addendum =201 ' You returned null. If your effect does not require clean ' +202 'up, return undefined (or nothing).';203 // $FlowFixMe[incompatible-type] (@poteto) this check is safe on arbitrary non-null/void objects204 } else if (typeof destroy.then === 'function') {205 addendum =206 '\n\nIt looks like you wrote ' +207 hookName +208 '(async () => ...) or returned a Promise. ' +209 'Instead, write the async function inside your effect ' +210 'and call it immediately:\n\n' +211 hookName +212 '(() => {\n' +213 ' async function fetchData() {\n' +214 ' // You can await here\n' +215 ' const response = await MyAPI.getData(someId);\n' +216 ' // ...\n' +217 ' }\n' +218 ' fetchData();\n' +219 `}, [someId]); // Or [] if effect doesn't need props or state\n\n` +220 'Learn more about data fetching with Hooks: https://react.dev/link/hooks-data-fetching';221 } else {222 // $FlowFixMe[unsafe-addition] (@poteto)223 addendum = ' You returned: ' + destroy;224 }225 runWithFiberInDEV(226 finishedWork,227 (n, a) => {228 console.error(229 '%s must not return anything besides a function, ' +230 'which is used for clean-up.%s',231 n,232 a,233 );234 },235 hookName,236 addendum,237 );238 }239 }240 }241 effect = effect.next;242 } while (effect !== firstEffect);243 }244 } catch (error) {245 captureCommitPhaseError(finishedWork, finishedWork.return, error);246 }247}248249export function commitHookEffectListUnmount(250 flags: HookFlags,251 finishedWork: Fiber,252 nearestMountedAncestor: Fiber | null,253) {254 try {255 const updateQueue: FunctionComponentUpdateQueue | null =256 finishedWork.updateQueue as any;257 const lastEffect = updateQueue !== null ? updateQueue.lastEffect : null;258 if (lastEffect !== null) {259 const firstEffect = lastEffect.next;260 let effect = firstEffect;261 do {262 if ((effect.tag & flags) === flags) {263 // Unmount264 const inst = effect.inst;265 const destroy = inst.destroy;266 if (destroy !== undefined) {267 inst.destroy = undefined;268 if (enableSchedulingProfiler) {269 if ((flags & HookPassive) !== NoHookEffect) {270 markComponentPassiveEffectUnmountStarted(finishedWork);271 } else if ((flags & HookLayout) !== NoHookEffect) {272 markComponentLayoutEffectUnmountStarted(finishedWork);273 }274 }275276 if (__DEV__) {277 if ((flags & HookInsertion) !== NoHookEffect) {278 setIsRunningInsertionEffect(true);279 }280 }281 safelyCallDestroy(finishedWork, nearestMountedAncestor, destroy);282 if (__DEV__) {283 if ((flags & HookInsertion) !== NoHookEffect) {284 setIsRunningInsertionEffect(false);285 }286 }287288 if (enableSchedulingProfiler) {289 if ((flags & HookPassive) !== NoHookEffect) {290 markComponentPassiveEffectUnmountStopped();291 } else if ((flags & HookLayout) !== NoHookEffect) {292 markComponentLayoutEffectUnmountStopped();293 }294 }295 }296 }297 effect = effect.next;298 } while (effect !== firstEffect);299 }300 } catch (error) {301 captureCommitPhaseError(finishedWork, finishedWork.return, error);302 }303}304305export function commitHookPassiveMountEffects(306 finishedWork: Fiber,307 hookFlags: HookFlags,308) {309 if (shouldProfile(finishedWork)) {310 startEffectTimer();311 commitHookEffectListMount(hookFlags, finishedWork);312 recordEffectDuration(finishedWork);313 } else {314 commitHookEffectListMount(hookFlags, finishedWork);315 }316}317318export function commitHookPassiveUnmountEffects(319 finishedWork: Fiber,320 nearestMountedAncestor: null | Fiber,321 hookFlags: HookFlags,322) {323 if (shouldProfile(finishedWork)) {324 startEffectTimer();325 commitHookEffectListUnmount(326 hookFlags,327 finishedWork,328 nearestMountedAncestor,329 );330 recordEffectDuration(finishedWork);331 } else {332 commitHookEffectListUnmount(333 hookFlags,334 finishedWork,335 nearestMountedAncestor,336 );337 }338}339340export function commitClassLayoutLifecycles(341 finishedWork: Fiber,342 current: Fiber | null,343) {344 const instance = finishedWork.stateNode;345 if (current === null) {346 // We could update instance props and state here,347 // but instead we rely on them being set during last render.348 // TODO: revisit this when we implement resuming.349 if (__DEV__) {350 if (351 !finishedWork.type.defaultProps &&352 !('ref' in finishedWork.memoizedProps) &&353 !didWarnAboutReassigningProps354 ) {355 if (instance.props !== finishedWork.memoizedProps) {356 console.error(357 'Expected %s props to match memoized props before ' +358 'componentDidMount. ' +359 'This might either be because of a bug in React, or because ' +360 'a component reassigns its own `this.props`. ' +361 'Please file an issue.',362 getComponentNameFromFiber(finishedWork) || 'instance',363 );364 }365 if (instance.state !== finishedWork.memoizedState) {366 console.error(367 'Expected %s state to match memoized state before ' +368 'componentDidMount. ' +369 'This might either be because of a bug in React, or because ' +370 'a component reassigns its own `this.state`. ' +371 'Please file an issue.',372 getComponentNameFromFiber(finishedWork) || 'instance',373 );374 }375 }376 }377 if (shouldProfile(finishedWork)) {378 startEffectTimer();379 if (__DEV__) {380 runWithFiberInDEV(381 finishedWork,382 callComponentDidMountInDEV,383 finishedWork,384 instance,385 );386 } else {387 try {388 instance.componentDidMount();389 } catch (error) {390 captureCommitPhaseError(finishedWork, finishedWork.return, error);391 }392 }393 recordEffectDuration(finishedWork);394 } else {395 if (__DEV__) {396 runWithFiberInDEV(397 finishedWork,398 callComponentDidMountInDEV,399 finishedWork,400 instance,401 );402 } else {403 try {404 instance.componentDidMount();405 } catch (error) {406 captureCommitPhaseError(finishedWork, finishedWork.return, error);407 }408 }409 }410 } else {411 const prevProps = resolveClassComponentProps(412 finishedWork.type,413 current.memoizedProps,414 );415 const prevState = current.memoizedState;416 // We could update instance props and state here,417 // but instead we rely on them being set during last render.418 // TODO: revisit this when we implement resuming.419 if (__DEV__) {420 if (421 !finishedWork.type.defaultProps &&422 !('ref' in finishedWork.memoizedProps) &&423 !didWarnAboutReassigningProps424 ) {425 if (instance.props !== finishedWork.memoizedProps) {426 console.error(427 'Expected %s props to match memoized props before ' +428 'componentDidUpdate. ' +429 'This might either be because of a bug in React, or because ' +430 'a component reassigns its own `this.props`. ' +431 'Please file an issue.',432 getComponentNameFromFiber(finishedWork) || 'instance',433 );434 }435 if (instance.state !== finishedWork.memoizedState) {436 console.error(437 'Expected %s state to match memoized state before ' +438 'componentDidUpdate. ' +439 'This might either be because of a bug in React, or because ' +440 'a component reassigns its own `this.state`. ' +441 'Please file an issue.',442 getComponentNameFromFiber(finishedWork) || 'instance',443 );444 }445 }446 }447 if (shouldProfile(finishedWork)) {448 startEffectTimer();449 if (__DEV__) {450 runWithFiberInDEV(451 finishedWork,452 callComponentDidUpdateInDEV,453 finishedWork,454 instance,455 prevProps,456 prevState,457 instance.__reactInternalSnapshotBeforeUpdate,458 );459 } else {460 try {461 instance.componentDidUpdate(462 prevProps,463 prevState,464 instance.__reactInternalSnapshotBeforeUpdate,465 );466 } catch (error) {467 captureCommitPhaseError(finishedWork, finishedWork.return, error);468 }469 }470 recordEffectDuration(finishedWork);471 } else {472 if (__DEV__) {473 runWithFiberInDEV(474 finishedWork,475 callComponentDidUpdateInDEV,476 finishedWork,477 instance,478 prevProps,479 prevState,480 instance.__reactInternalSnapshotBeforeUpdate,481 );482 } else {483 try {484 instance.componentDidUpdate(485 prevProps,486 prevState,487 instance.__reactInternalSnapshotBeforeUpdate,488 );489 } catch (error) {490 captureCommitPhaseError(finishedWork, finishedWork.return, error);491 }492 }493 }494 }495}496497export function commitClassDidMount(finishedWork: Fiber) {498 // TODO: Check for LayoutStatic flag499 const instance = finishedWork.stateNode;500 if (typeof instance.componentDidMount === 'function') {501 if (__DEV__) {502 runWithFiberInDEV(503 finishedWork,504 callComponentDidMountInDEV,505 finishedWork,506 instance,507 );508 } else {509 try {510 instance.componentDidMount();511 } catch (error) {512 captureCommitPhaseError(finishedWork, finishedWork.return, error);513 }514 }515 }516}517518export function commitClassCallbacks(finishedWork: Fiber) {519 // TODO: I think this is now always non-null by the time it reaches the520 // commit phase. Consider removing the type check.521 const updateQueue: UpdateQueue<mixed> | null =522 finishedWork.updateQueue as any;523 if (updateQueue !== null) {524 const instance = finishedWork.stateNode;525 if (__DEV__) {526 if (527 !finishedWork.type.defaultProps &&528 !('ref' in finishedWork.memoizedProps) &&529 !didWarnAboutReassigningProps530 ) {531 if (instance.props !== finishedWork.memoizedProps) {532 console.error(533 'Expected %s props to match memoized props before ' +534 'processing the update queue. ' +535 'This might either be because of a bug in React, or because ' +536 'a component reassigns its own `this.props`. ' +537 'Please file an issue.',538 getComponentNameFromFiber(finishedWork) || 'instance',539 );540 }541 if (instance.state !== finishedWork.memoizedState) {542 console.error(543 'Expected %s state to match memoized state before ' +544 'processing the update queue. ' +545 'This might either be because of a bug in React, or because ' +546 'a component reassigns its own `this.state`. ' +547 'Please file an issue.',548 getComponentNameFromFiber(finishedWork) || 'instance',549 );550 }551 }552 }553 // We could update instance props and state here,554 // but instead we rely on them being set during last render.555 // TODO: revisit this when we implement resuming.556 try {557 if (__DEV__) {558 runWithFiberInDEV(finishedWork, commitCallbacks, updateQueue, instance);559 } else {560 commitCallbacks(updateQueue, instance);561 }562 } catch (error) {563 captureCommitPhaseError(finishedWork, finishedWork.return, error);564 }565 }566}567568export function commitClassHiddenCallbacks(finishedWork: Fiber) {569 // Commit any callbacks that would have fired while the component570 // was hidden.571 const updateQueue: UpdateQueue<mixed> | null =572 finishedWork.updateQueue as any;573 if (updateQueue !== null) {574 const instance = finishedWork.stateNode;575 try {576 if (__DEV__) {577 runWithFiberInDEV(578 finishedWork,579 commitHiddenCallbacks,580 updateQueue,581 instance,582 );583 } else {584 commitHiddenCallbacks(updateQueue, instance);585 }586 } catch (error) {587 captureCommitPhaseError(finishedWork, finishedWork.return, error);588 }589 }590}591592export function commitRootCallbacks(finishedWork: Fiber) {593 // TODO: I think this is now always non-null by the time it reaches the594 // commit phase. Consider removing the type check.595 const updateQueue: UpdateQueue<mixed> | null =596 finishedWork.updateQueue as any;597 if (updateQueue !== null) {598 let instance = null;599 if (finishedWork.child !== null) {600 switch (finishedWork.child.tag) {601 case HostSingleton:602 case HostComponent:603 instance = getPublicInstance(finishedWork.child.stateNode);604 break;605 case ClassComponent:606 instance = finishedWork.child.stateNode;607 break;608 }609 }610 try {611 if (__DEV__) {612 runWithFiberInDEV(finishedWork, commitCallbacks, updateQueue, instance);613 } else {614 commitCallbacks(updateQueue, instance);615 }616 } catch (error) {617 captureCommitPhaseError(finishedWork, finishedWork.return, error);618 }619 }620}621622let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;623if (__DEV__) {624 didWarnAboutUndefinedSnapshotBeforeUpdate = new Set();625}626627function callGetSnapshotBeforeUpdates(628 instance: any,629 prevProps: any,630 prevState: any,631) {632 return instance.getSnapshotBeforeUpdate(prevProps, prevState);633}634635export function commitClassSnapshot(finishedWork: Fiber, current: Fiber) {636 const prevProps = current.memoizedProps;637 const prevState = current.memoizedState;638 const instance = finishedWork.stateNode;639 // We could update instance props and state here,640 // but instead we rely on them being set during last render.641 // TODO: revisit this when we implement resuming.642 if (__DEV__) {643 if (644 !finishedWork.type.defaultProps &&645 !('ref' in finishedWork.memoizedProps) &&646 !didWarnAboutReassigningProps647 ) {648 if (instance.props !== finishedWork.memoizedProps) {649 console.error(650 'Expected %s props to match memoized props before ' +651 'getSnapshotBeforeUpdate. ' +652 'This might either be because of a bug in React, or because ' +653 'a component reassigns its own `this.props`. ' +654 'Please file an issue.',655 getComponentNameFromFiber(finishedWork) || 'instance',656 );657 }658 if (instance.state !== finishedWork.memoizedState) {659 console.error(660 'Expected %s state to match memoized state before ' +661 'getSnapshotBeforeUpdate. ' +662 'This might either be because of a bug in React, or because ' +663 'a component reassigns its own `this.state`. ' +664 'Please file an issue.',665 getComponentNameFromFiber(finishedWork) || 'instance',666 );667 }668 }669 }670 try {671 const resolvedPrevProps = resolveClassComponentProps(672 finishedWork.type,673 prevProps,674 );675 let snapshot;676 if (__DEV__) {677 snapshot = runWithFiberInDEV(678 finishedWork,679 callGetSnapshotBeforeUpdates,680 instance,681 resolvedPrevProps,682 prevState,683 );684 const didWarnSet =685 didWarnAboutUndefinedSnapshotBeforeUpdate as any as Set<mixed>;686 if (snapshot === undefined && !didWarnSet.has(finishedWork.type)) {687 didWarnSet.add(finishedWork.type);688 runWithFiberInDEV(finishedWork, () => {689 console.error(690 '%s.getSnapshotBeforeUpdate(): A snapshot value (or null) ' +691 'must be returned. You have returned undefined.',692 getComponentNameFromFiber(finishedWork),693 );694 });695 }696 } else {697 snapshot = callGetSnapshotBeforeUpdates(698 instance,699 resolvedPrevProps,700 prevState,701 );702 }703 instance.__reactInternalSnapshotBeforeUpdate = snapshot;704 } catch (error) {705 captureCommitPhaseError(finishedWork, finishedWork.return, error);706 }707}708709// Capture errors so they don't interrupt unmounting.710export function safelyCallComponentWillUnmount(711 current: Fiber,712 nearestMountedAncestor: Fiber | null,713 instance: any,714) {715 instance.props = resolveClassComponentProps(716 current.type,717 current.memoizedProps,718 );719 instance.state = current.memoizedState;720 if (shouldProfile(current)) {721 startEffectTimer();722 if (__DEV__) {723 runWithFiberInDEV(724 current,725 callComponentWillUnmountInDEV,726 current,727 nearestMountedAncestor,728 instance,729 );730 } else {731 try {732 instance.componentWillUnmount();733 } catch (error) {734 captureCommitPhaseError(current, nearestMountedAncestor, error);735 }736 }737 recordEffectDuration(current);738 } else {739 if (__DEV__) {740 runWithFiberInDEV(741 current,742 callComponentWillUnmountInDEV,743 current,744 nearestMountedAncestor,745 instance,746 );747 } else {748 try {749 instance.componentWillUnmount();750 } catch (error) {751 captureCommitPhaseError(current, nearestMountedAncestor, error);752 }753 }754 }755}756757function commitAttachRef(finishedWork: Fiber) {758 const ref = finishedWork.ref;759 if (ref !== null) {760 let instanceToUse;761 switch (finishedWork.tag) {762 case HostHoistable:763 case HostSingleton:764 case HostComponent:765 instanceToUse = getPublicInstance(finishedWork.stateNode);766 break;767 case ViewTransitionComponent: {768 if (enableViewTransition) {769 const instance: ViewTransitionState = finishedWork.stateNode;770 const props: ViewTransitionProps = finishedWork.memoizedProps;771 const name = getViewTransitionName(props, instance);772 if (instance.ref === null || instance.ref.name !== name) {773 instance.ref = createViewTransitionInstance(name);774 }775 instanceToUse = instance.ref;776 break;777 }778 instanceToUse = finishedWork.stateNode;779 break;780 }781 case Fragment:782 if (enableFragmentRefs) {783 const instance: null | FragmentInstanceType = finishedWork.stateNode;784 if (instance === null) {785 finishedWork.stateNode = createFragmentInstance(finishedWork);786 }787 instanceToUse = finishedWork.stateNode;788 break;789 }790 // Fallthrough791 default:792 instanceToUse = finishedWork.stateNode;793 }794 if (typeof ref === 'function') {795 if (shouldProfile(finishedWork)) {796 try {797 startEffectTimer();798 finishedWork.refCleanup = ref(instanceToUse);799 } finally {800 recordEffectDuration(finishedWork);801 }802 } else {803 finishedWork.refCleanup = ref(instanceToUse);804 }805 } else {806 if (__DEV__) {807 // TODO: We should move these warnings to happen during the render808 // phase (markRef).809 if (typeof ref === 'string') {810 console.error('String refs are no longer supported.');811 } else if (!ref.hasOwnProperty('current')) {812 console.error(813 'Unexpected ref object provided for %s. ' +814 'Use either a ref-setter function or React.createRef().',815 getComponentNameFromFiber(finishedWork),816 );817 }818 }819820 // $FlowFixMe[incompatible-use] unable to narrow type to the non-function case821 ref.current = instanceToUse;822 }823 }824}825826// Capture errors so they don't interrupt mounting.827export function safelyAttachRef(828 current: Fiber,829 nearestMountedAncestor: Fiber | null,830) {831 try {832 if (__DEV__) {833 runWithFiberInDEV(current, commitAttachRef, current);834 } else {835 commitAttachRef(current);836 }837 } catch (error) {838 captureCommitPhaseError(current, nearestMountedAncestor, error);839 }840}841842export function safelyDetachRef(843 current: Fiber,844 nearestMountedAncestor: Fiber | null,845) {846 const ref = current.ref;847 const refCleanup = current.refCleanup;848849 if (ref !== null) {850 if (typeof refCleanup === 'function') {851 try {852 if (shouldProfile(current)) {853 try {854 startEffectTimer();855 if (__DEV__) {856 runWithFiberInDEV(current, refCleanup);857 } else {858 refCleanup();859 }860 } finally {861 recordEffectDuration(current);862 }863 } else {864 if (__DEV__) {865 runWithFiberInDEV(current, refCleanup);866 } else {867 refCleanup();868 }869 }870 } catch (error) {871 captureCommitPhaseError(current, nearestMountedAncestor, error);872 } finally {873 // `refCleanup` has been called. Nullify all references to it to prevent double invocation.874 current.refCleanup = null;875 const finishedWork = current.alternate;876 if (finishedWork != null) {877 finishedWork.refCleanup = null;878 }879 }880 } else if (typeof ref === 'function') {881 try {882 if (shouldProfile(current)) {883 try {884 startEffectTimer();885 if (__DEV__) {886 runWithFiberInDEV(current, ref, null) as void;887 } else {888 ref(null);889 }890 } finally {891 recordEffectDuration(current);892 }893 } else {894 if (__DEV__) {895 runWithFiberInDEV(current, ref, null) as void;896 } else {897 ref(null);898 }899 }900 } catch (error) {901 captureCommitPhaseError(current, nearestMountedAncestor, error);902 }903 } else {904 // $FlowFixMe[incompatible-use] unable to narrow type to RefObject905 ref.current = null;906 }907 }908}909910function safelyCallDestroy(911 current: Fiber,912 nearestMountedAncestor: Fiber | null,913 destroy: (() => void) | (({...}) => void),914 resource?: {...} | void | null,915) {916 // $FlowFixMe[extra-arg] @poteto this is safe either way because the extra arg is ignored if it's not a CRUD effect917 const destroy_ = resource == null ? destroy : destroy.bind(null, resource);918 if (__DEV__) {919 runWithFiberInDEV(920 current,921 callDestroyInDEV,922 current,923 nearestMountedAncestor,924 destroy_,925 );926 } else {927 try {928 // $FlowFixMe[incompatible-type](incompatible-call) Already bound to resource929 destroy_();930 } catch (error) {931 captureCommitPhaseError(current, nearestMountedAncestor, error);932 }933 }934}935936function commitProfiler(937 finishedWork: Fiber,938 current: Fiber | null,939 commitStartTime: number,940 effectDuration: number,941) {942 const {id, onCommit, onRender} = finishedWork.memoizedProps as ProfilerProps;943944 let phase: ProfilerPhase = current === null ? 'mount' : 'update';945 if (enableProfilerNestedUpdatePhase) {946 if (isCurrentUpdateNested()) {947 phase = 'nested-update';948 }949 }950951 if (typeof onRender === 'function') {952 onRender(953 id,954 phase,955 // $FlowFixMe[incompatible-type]: This should be always a number in profiling mode956 finishedWork.actualDuration,957 // $FlowFixMe[incompatible-type]: This should be always a number in profiling mode958 finishedWork.treeBaseDuration,959 // $FlowFixMe[incompatible-type]: This should be always a number in profiling mode960 finishedWork.actualStartTime,961 commitStartTime,962 );963 }964965 if (enableProfilerCommitHooks) {966 if (typeof onCommit === 'function') {967 onCommit(id, phase, effectDuration, commitStartTime);968 }969 }970}971972export function commitProfilerUpdate(973 finishedWork: Fiber,974 current: Fiber | null,975 commitStartTime: number,976 effectDuration: number,977) {978 if (enableProfilerTimer) {979 try {980 if (__DEV__) {981 runWithFiberInDEV(982 finishedWork,983 commitProfiler,984 finishedWork,985 current,986 commitStartTime,987 effectDuration,988 );989 } else {990 commitProfiler(finishedWork, current, commitStartTime, effectDuration);991 }992 } catch (error) {993 captureCommitPhaseError(finishedWork, finishedWork.return, error);994 }995 }996}997998function commitProfilerPostCommitImpl(999 finishedWork: Fiber,1000 current: Fiber | null,1001 commitStartTime: number,1002 passiveEffectDuration: number,1003): void {1004 const {id, onPostCommit} = finishedWork.memoizedProps;10051006 let phase = current === null ? 'mount' : 'update';1007 if (enableProfilerNestedUpdatePhase) {1008 if (isCurrentUpdateNested()) {1009 phase = 'nested-update';1010 }1011 }10121013 if (typeof onPostCommit === 'function') {1014 onPostCommit(id, phase, passiveEffectDuration, commitStartTime);1015 }1016}10171018export function commitProfilerPostCommit(1019 finishedWork: Fiber,1020 current: Fiber | null,1021 commitStartTime: number,1022 passiveEffectDuration: number,1023) {1024 try {1025 if (__DEV__) {1026 runWithFiberInDEV(1027 finishedWork,1028 commitProfilerPostCommitImpl,1029 finishedWork,1030 current,1031 commitStartTime,1032 passiveEffectDuration,1033 );1034 } else {1035 commitProfilerPostCommitImpl(1036 finishedWork,1037 current,1038 commitStartTime,1039 passiveEffectDuration,1040 );1041 }1042 } catch (error) {1043 captureCommitPhaseError(finishedWork, finishedWork.return, error);1044 }1045}
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.