var callComponentWillUnmountWithTimerInDev = function(current, instance) { startPhaseTimer(current, 'componentWillUnmount'); instance.props = current.memoizedProps; instance.state = current.memoizedState; instance.componentWillUnmount(); stopPhaseTimer(); };
function callComponentWillReceiveProps( workInProgress, instance, newProps, newContext, ) { if (__DEV__) { startPhaseTimer(workInProgress, 'componentWillReceiveProps'); } const oldState = instance.state; instance.componentWillReceiveProps(newProps, newContext); if (__DEV__) { stopPhaseTimer(); } if (instance.state !== oldState) { if (__DEV__) { warning( false, '%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName(workInProgress), ); } updater.enqueueReplaceState(instance, instance.state, null); } }
// Invokes the mount life-cycles on a previously never rendered instance. function mountClassInstance( workInProgress: Fiber, priorityLevel: PriorityLevel, ): void { if (__DEV__) { checkClassInstance(workInProgress); } const instance = workInProgress.stateNode; const state = instance.state || null; let props = workInProgress.pendingProps; invariant( props, 'There must be pending props for an initial mount. This error is ' + 'likely caused by a bug in React. Please file an issue.', ); const unmaskedContext = getUnmaskedContext(workInProgress); instance.props = props; instance.state = state; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); if ( ReactFeatureFlags.enableAsyncSubtreeAPI && workInProgress.type != null && workInProgress.type.unstable_asyncUpdates === true ) { workInProgress.internalContextTag |= AsyncUpdates; } if (typeof instance.componentWillMount === 'function') { if (__DEV__) { startPhaseTimer(workInProgress, 'componentWillMount'); } instance.componentWillMount(); if (__DEV__) { stopPhaseTimer(); } // If we had additional state updates during this life-cycle, let's // process them now. const updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { instance.state = beginUpdateQueue( workInProgress, updateQueue, instance, state, props, priorityLevel, ); } } if (typeof instance.componentDidMount === 'function') { workInProgress.effectTag |= Update; } }
function checkShouldComponentUpdate( workInProgress, oldProps, newProps, oldState, newState, newContext, ) { if ( oldProps === null || (workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate) ) { // If the workInProgress already has an Update effect, return true return true; } const instance = workInProgress.stateNode; const type = workInProgress.type; if (typeof instance.shouldComponentUpdate === 'function') { if (__DEV__) { startPhaseTimer(workInProgress, 'shouldComponentUpdate'); } const shouldUpdate = instance.shouldComponentUpdate( newProps, newState, newContext, ); if (__DEV__) { stopPhaseTimer(); } if (__DEV__) { warning( shouldUpdate !== undefined, '%s.shouldComponentUpdate(): Returned undefined instead of a ' + 'boolean value. Make sure to return true or false.', getComponentName(workInProgress) || 'Unknown', ); } return shouldUpdate; } if (type.prototype && type.prototype.isPureReactComponent) { return ( !shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState) ); } return true; }
// Called on a preexisting class instance. Returns false if a resumed render // could be reused. // function resumeMountClassInstance( // workInProgress: Fiber, // priorityLevel: PriorityLevel, // ): boolean { // const instance = workInProgress.stateNode; // resetInputPointers(workInProgress, instance); // let newState = workInProgress.memoizedState; // let newProps = workInProgress.pendingProps; // if (!newProps) { // // If there isn't any new props, then we'll reuse the memoized props. // // This could be from already completed work. // newProps = workInProgress.memoizedProps; // invariant( // newProps != null, // 'There should always be pending or memoized props. This error is ' + // 'likely caused by a bug in React. Please file an issue.', // ); // } // const newUnmaskedContext = getUnmaskedContext(workInProgress); // const newContext = getMaskedContext(workInProgress, newUnmaskedContext); // const oldContext = instance.context; // const oldProps = workInProgress.memoizedProps; // if ( // typeof instance.componentWillReceiveProps === 'function' && // (oldProps !== newProps || oldContext !== newContext) // ) { // callComponentWillReceiveProps( // workInProgress, // instance, // newProps, // newContext, // ); // } // // Process the update queue before calling shouldComponentUpdate // const updateQueue = workInProgress.updateQueue; // if (updateQueue !== null) { // newState = beginUpdateQueue( // workInProgress, // updateQueue, // instance, // newState, // newProps, // priorityLevel, // ); // } // // TODO: Should we deal with a setState that happened after the last // // componentWillMount and before this componentWillMount? Probably // // unsupported anyway. // if ( // !checkShouldComponentUpdate( // workInProgress, // workInProgress.memoizedProps, // newProps, // workInProgress.memoizedState, // newState, // newContext, // ) // ) { // // Update the existing instance's state, props, and context pointers even // // though we're bailing out. // instance.props = newProps; // instance.state = newState; // instance.context = newContext; // return false; // } // // Update the input pointers now so that they are correct when we call // // componentWillMount // instance.props = newProps; // instance.state = newState; // instance.context = newContext; // if (typeof instance.componentWillMount === 'function') { // callComponentWillMount(workInProgress, instance); // // componentWillMount may have called setState. Process the update queue. // const newUpdateQueue = workInProgress.updateQueue; // if (newUpdateQueue !== null) { // newState = beginUpdateQueue( // workInProgress, // newUpdateQueue, // instance, // newState, // newProps, // priorityLevel, // ); // } // } // if (typeof instance.componentDidMount === 'function') { // workInProgress.effectTag |= Update; // } // instance.state = newState; // return true; // } // Invokes the update life-cycles and returns false if it shouldn't rerender. function updateClassInstance( current: Fiber, workInProgress: Fiber, priorityLevel: PriorityLevel, ): boolean { const instance = workInProgress.stateNode; resetInputPointers(workInProgress, instance); const oldProps = workInProgress.memoizedProps; let newProps = workInProgress.pendingProps; if (!newProps) { // If there aren't any new props, then we'll reuse the memoized props. // This could be from already completed work. newProps = oldProps; invariant( newProps != null, 'There should always be pending or memoized props. This error is ' + 'likely caused by a bug in React. Please file an issue.', ); } const oldContext = instance.context; const newUnmaskedContext = getUnmaskedContext(workInProgress); const newContext = getMaskedContext(workInProgress, newUnmaskedContext); // Note: During these life-cycles, instance.props/instance.state are what // ever the previously attempted to render - not the "current". However, // during componentDidUpdate we pass the "current" props. if ( typeof instance.componentWillReceiveProps === 'function' && (oldProps !== newProps || oldContext !== newContext) ) { callComponentWillReceiveProps( workInProgress, instance, newProps, newContext, ); } // Compute the next state using the memoized state and the update queue. const oldState = workInProgress.memoizedState; // TODO: Previous state can be null. let newState; if (workInProgress.updateQueue !== null) { newState = beginUpdateQueue( current, workInProgress, workInProgress.updateQueue, instance, oldState, newProps, priorityLevel, ); } else { newState = oldState; } if ( oldProps === newProps && oldState === newState && !hasContextChanged() && !(workInProgress.updateQueue !== null && workInProgress.updateQueue.hasForceUpdate) ) { // If an update was already in progress, we should schedule an Update // effect even though we're bailing out, so that cWU/cDU are called. if (typeof instance.componentDidUpdate === 'function') { if ( oldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.effectTag |= Update; } } return false; } const shouldUpdate = checkShouldComponentUpdate( workInProgress, oldProps, newProps, oldState, newState, newContext, ); if (shouldUpdate) { if (typeof instance.componentWillUpdate === 'function') { if (__DEV__) { startPhaseTimer(workInProgress, 'componentWillUpdate'); } instance.componentWillUpdate(newProps, newState, newContext); if (__DEV__) { stopPhaseTimer(); } } if (typeof instance.componentDidUpdate === 'function') { workInProgress.effectTag |= Update; } } else { // If an update was already in progress, we should schedule an Update // effect even though we're bailing out, so that cWU/cDU are called. if (typeof instance.componentDidUpdate === 'function') { if ( oldProps !== current.memoizedProps || oldState !== current.memoizedState ) { workInProgress.effectTag |= Update; } } // If shouldComponentUpdate returned false, we should still update the // memoized props/state to indicate that this work can be reused. memoizeProps(workInProgress, newProps); memoizeState(workInProgress, newState); } // Update the existing instance's state, props, and context pointers even // if shouldComponentUpdate returns false. instance.props = newProps; instance.state = newState; instance.context = newContext; return shouldUpdate; }
function processChildContext( fiber: Fiber, parentContext: Object, isReconciling: boolean, ): Object { const instance = fiber.stateNode; const childContextTypes = fiber.type.childContextTypes; // TODO (bvaughn) Replace this behavior with an invariant() in the future. // It has only been added in Fiber to match the (unintentional) behavior in Stack. if (typeof instance.getChildContext !== 'function') { if (__DEV__) { const componentName = getComponentName(fiber) || 'Unknown'; if (!warnedAboutMissingGetChildContext[componentName]) { warnedAboutMissingGetChildContext[componentName] = true; warning( false, '%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName, ); } } return parentContext; } let childContext; if (__DEV__) { ReactDebugCurrentFiber.setCurrentFiber(fiber, 'getChildContext'); startPhaseTimer(fiber, 'getChildContext'); childContext = instance.getChildContext(); stopPhaseTimer(); ReactDebugCurrentFiber.resetCurrentFiber(); } else { childContext = instance.getChildContext(); } for (let contextKey in childContext) { invariant( contextKey in childContextTypes, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', getComponentName(fiber) || 'Unknown', contextKey, ); } if (__DEV__) { const name = getComponentName(fiber) || 'Unknown'; // We can only provide accurate element stacks if we pass work-in-progress tree // during the begin or complete phase. However currently this function is also // called from unstable_renderSubtree legacy implementation. In this case it unsafe to // assume anything about the given fiber. We won't pass it down if we aren't sure. // TODO: remove this hack when we delete unstable_renderSubtree in Fiber. const workInProgress = isReconciling ? fiber : null; ReactDebugCurrentFiber.setCurrentFiber(workInProgress, null); checkPropTypes( childContextTypes, childContext, 'child context', name, ReactDebugCurrentFiber.getCurrentFiberStackAddendum, ); ReactDebugCurrentFiber.resetCurrentFiber(); } return {...parentContext, ...childContext}; }
var callComponentWillUnmountWithTimerInDev = function(current, instance) { startPhaseTimer(current, 'componentWillUnmount'); instance.componentWillUnmount(); stopPhaseTimer(); };
function commitLifeCycles(current: Fiber | null, finishedWork: Fiber): void { switch (finishedWork.tag) { case ClassComponent: { const instance = finishedWork.stateNode; if (finishedWork.effectTag & Update) { if (current === null) { if (__DEV__) { startPhaseTimer(finishedWork, 'componentDidMount'); } instance.componentDidMount(); if (__DEV__) { stopPhaseTimer(); } } else { const prevProps = current.memoizedProps; const prevState = current.memoizedState; if (__DEV__) { startPhaseTimer(finishedWork, 'componentDidUpdate'); } instance.componentDidUpdate(prevProps, prevState); if (__DEV__) { stopPhaseTimer(); } } } if ( finishedWork.effectTag & Callback && finishedWork.updateQueue !== null ) { commitCallbacks(finishedWork, finishedWork.updateQueue, instance); } return; } case HostRoot: { const updateQueue = finishedWork.updateQueue; if (updateQueue !== null) { const instance = finishedWork.child && finishedWork.child.stateNode; commitCallbacks(finishedWork, updateQueue, instance); } return; } case HostComponent: { const instance: I = finishedWork.stateNode; // Renderers may schedule work to be done after host components are mounted // (eg DOM renderer may schedule auto-focus for inputs and form controls). // These effects should only be committed when components are first mounted, // aka when there is no current/alternate. if (current === null && finishedWork.effectTag & Update) { const type = finishedWork.type; const props = finishedWork.memoizedProps; commitMount(instance, type, props, finishedWork); } return; } case HostText: { // We have no life-cycles associated with text. return; } case HostPortal: { // We have no life-cycles associated with portals. return; } default: { invariant( false, 'This unit of work tag should not have side-effects. This error is ' + 'likely caused by a bug in React. Please file an issue.', ); } } }
function processChildContext(fiber: Fiber, parentContext: Object): Object { const instance = fiber.stateNode; const childContextTypes = fiber.type.childContextTypes; // TODO (bvaughn) Replace this behavior with an invariant() in the future. // It has only been added in Fiber to match the (unintentional) behavior in Stack. if (typeof instance.getChildContext !== 'function') { if (__DEV__) { const componentName = getComponentName(fiber) || 'Unknown'; if (!warnedAboutMissingGetChildContext[componentName]) { warnedAboutMissingGetChildContext[componentName] = true; warning( false, '%s.childContextTypes is specified but there is no getChildContext() method ' + 'on the instance. You can either define getChildContext() on %s or remove ' + 'childContextTypes from it.', componentName, componentName, ); } } return parentContext; } let childContext; if (__DEV__) { ReactDebugCurrentFiber.setCurrentPhase('getChildContext'); startPhaseTimer(fiber, 'getChildContext'); childContext = instance.getChildContext(); stopPhaseTimer(); ReactDebugCurrentFiber.setCurrentPhase(null); } else { childContext = instance.getChildContext(); } for (let contextKey in childContext) { invariant( contextKey in childContextTypes, '%s.getChildContext(): key "%s" is not defined in childContextTypes.', getComponentName(fiber) || 'Unknown', contextKey, ); } if (__DEV__) { const name = getComponentName(fiber) || 'Unknown'; checkPropTypes( childContextTypes, childContext, 'child context', name, // In practice, there is one case in which we won't get a stack. It's when // somebody calls unstable_renderSubtreeIntoContainer() and we process // context from the parent component instance. The stack will be missing // because it's outside of the reconciliation, and so the pointer has not // been set. This is rare and doesn't matter. We'll also remove that API. ReactDebugCurrentFiber.getCurrentFiberStackAddendum, ); } return {...parentContext, ...childContext}; }
// Called on a preexisting class instance. Returns false if a resumed render // could be reused. function resumeMountClassInstance(workInProgress : Fiber, priorityLevel : PriorityLevel) : boolean { const instance = workInProgress.stateNode; resetInputPointers(workInProgress, instance); let newState = workInProgress.memoizedState; let newProps = workInProgress.pendingProps; if (!newProps) { // If there isn't any new props, then we'll reuse the memoized props. // This could be from already completed work. newProps = workInProgress.memoizedProps; invariant( newProps != null, 'There should always be pending or memoized props. This error is ' + 'likely caused by a bug in React. Please file an issue.' ); } const newUnmaskedContext = getUnmaskedContext(workInProgress); const newContext = getMaskedContext(workInProgress, newUnmaskedContext); // TODO: Should we deal with a setState that happened after the last // componentWillMount and before this componentWillMount? Probably // unsupported anyway. if (!checkShouldComponentUpdate( workInProgress, workInProgress.memoizedProps, newProps, workInProgress.memoizedState, newState, newContext )) { // Update the existing instance's state, props, and context pointers even // though we're bailing out. instance.props = newProps; instance.state = newState; instance.context = newContext; return false; } // If we didn't bail out we need to construct a new instance. We don't // want to reuse one that failed to fully mount. const newInstance = constructClassInstance(workInProgress); newInstance.props = newProps; newInstance.state = newState = newInstance.state || null; newInstance.context = newContext; if (typeof newInstance.componentWillMount === 'function') { if (__DEV__) { startPhaseTimer(workInProgress, 'componentWillMount'); } newInstance.componentWillMount(); if (__DEV__) { stopPhaseTimer(); } } // If we had additional state updates, process them now. // They may be from componentWillMount() or from error boundary's setState() // during initial mounting. const newUpdateQueue = workInProgress.updateQueue; if (newUpdateQueue !== null) { newInstance.state = beginUpdateQueue( workInProgress, newUpdateQueue, newInstance, newState, newProps, priorityLevel ); } if (typeof instance.componentDidMount === 'function') { workInProgress.effectTag |= Update; } return true; }