function validateClassInstance(inst, methodName) { if (!inst) { // This is probably too relaxed but it's existing behavior. return; } if (ReactInstanceMap.get(inst)) { // This is a public instance indeed. return; } let received; const stringified = '' + inst; if (Array.isArray(inst)) { received = 'an array'; } else if (inst && inst.nodeType === 1 && inst.tagName) { received = 'a DOM node'; } else if (stringified === '[object Object]') { received = 'object with keys {' + Object.keys(inst).join(', ') + '}'; } else { received = stringified; } invariant( false, '%s(...): the first argument must be a React class instance. ' + 'Instead received: %s.', methodName, received, ); }
function findHostInstanceWithWarning( component: Object, methodName: string, ): PublicInstance | null { if (__DEV__) { const fiber = getInstance(component); if (fiber === undefined) { if (typeof component.render === 'function') { invariant(false, 'Unable to find node on an unmounted component.'); } else { invariant( false, 'Argument appears to not be a ReactComponent. Keys: %s', Object.keys(component), ); } } const hostFiber = findCurrentHostFiber(fiber); if (hostFiber === null) { return null; } if (hostFiber.mode & StrictMode) { const componentName = getComponentName(fiber.type) || 'Component'; if (!didWarnAboutFindNodeInStrictMode[componentName]) { didWarnAboutFindNodeInStrictMode[componentName] = true; if (fiber.mode & StrictMode) { warningWithoutStack( false, '%s is deprecated in StrictMode. ' + '%s was passed an instance of %s which is inside StrictMode. ' + 'Instead, add a ref directly to the element you want to reference.' + '\n%s' + '\n\nLearn more about using refs safely here:' + '\nhttps://fb.me/react-strict-mode-find-node', methodName, methodName, componentName, getStackByFiberInDevAndProd(hostFiber), ); } else { warningWithoutStack( false, '%s is deprecated in StrictMode. ' + '%s was passed an instance of %s which renders StrictMode children. ' + 'Instead, add a ref directly to the element you want to reference.' + '\n%s' + '\n\nLearn more about using refs safely here:' + '\nhttps://fb.me/react-strict-mode-find-node', methodName, methodName, componentName, getStackByFiberInDevAndProd(hostFiber), ); } } } return hostFiber.stateNode; } return findHostInstance(component); }
export function isMounted(component: React$Component<any, any>): boolean { if (__DEV__) { const owner = (ReactCurrentOwner.current: any); if (owner !== null && owner.tag === ClassComponent) { const ownerFiber: Fiber = owner; const instance = ownerFiber.stateNode; warningWithoutStack( instance._warnedAboutRefsInRender, '%s is accessing isMounted inside its render() function. ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(ownerFiber.type) || 'A component', ); instance._warnedAboutRefsInRender = true; } } const fiber: ?Fiber = ReactInstanceMap.get(component); if (!fiber) { return false; } return isFiberMountedImpl(fiber) === MOUNTED; }
findAllInRenderedTree: function(inst, test) { validateClassInstance(inst, 'findAllInRenderedTree'); if (!inst) { return []; } const internalInstance = ReactInstanceMap.get(inst); return findAllInRenderedFiberTreeInternal(internalInstance, test); },
isCompositeComponentWithType: function(inst, type) { if (!ReactTestUtils.isCompositeComponent(inst)) { return false; } const internalInstance = ReactInstanceMap.get(inst); const constructor = internalInstance.type; return constructor === type; },
/** * ReactNative vs ReactWeb * ----------------------- * React treats some pieces of data opaquely. This means that the information * is first class (it can be passed around), but cannot be inspected. This * allows us to build infrastructure that reasons about resources, without * making assumptions about the nature of those resources, and this allows that * infra to be shared across multiple platforms, where the resources are very * different. General infra (such as `ReactMultiChild`) reasons opaquely about * the data, but platform specific code (such as `ReactNativeBaseComponent`) can * make assumptions about the data. * * * `rootNodeID`, uniquely identifies a position in the generated native view * tree. Many layers of composite components (created with `React.createClass`) * can all share the same `rootNodeID`. * * `nodeHandle`: A sufficiently unambiguous way to refer to a lower level * resource (dom node, native view etc). The `rootNodeID` is sufficient for web * `nodeHandle`s, because the position in a tree is always enough to uniquely * identify a DOM node (we never have nodes in some bank outside of the * document). The same would be true for `ReactNative`, but we must maintain a * mapping that we can send efficiently serializable * strings across native boundaries. * * Opaque name TodaysWebReact FutureWebWorkerReact ReactNative * ---------------------------------------------------------------------------- * nodeHandle N/A rootNodeID tag */ // TODO (bvaughn) Rename the findNodeHandle module to something more descriptive // eg findInternalHostInstance. This will reduce the likelihood of someone // accidentally deep-requiring this version. function findNodeHandle(componentOrHandle: any): any { if (__DEV__) { const owner = ReactCurrentOwner.current; if (owner !== null && owner.stateNode !== null) { warning( owner.stateNode._warnedAboutRefsInRender, '%s is accessing findNodeHandle inside its render(). ' + 'render() should be a pure function of props and state. It should ' + 'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(owner) || 'A component', ); owner.stateNode._warnedAboutRefsInRender = true; } } if (componentOrHandle == null) { return null; } if (typeof componentOrHandle === 'number') { // Already a node handle return componentOrHandle; } const component = componentOrHandle; // TODO (balpert): Wrap iOS native components in a composite wrapper, then // ReactInstanceMap.get here will always succeed for mounted components const internalInstance: Fiber = ReactInstanceMap.get(component); if (internalInstance) { return ReactNativeFiberRenderer.findHostInstance(internalInstance); } else { if (component) { return component; } else { invariant( // Native (typeof component === 'object' && '_nativeTag' in component) || // Composite (component.render != null && typeof component.render === 'function'), 'findNodeHandle(...): Argument is not a component ' + '(type: %s, keys: %s)', typeof component, Object.keys(component), ); invariant( false, 'findNodeHandle(...): Unable to find node handle for unmounted ' + 'component.', ); } } }
findAllInRenderedTree: function(inst, test) { if (!inst) { return []; } invariant( ReactTestUtils.isCompositeComponent(inst), 'findAllInRenderedTree(...): instance must be a composite component', ); const internalInstance = ReactInstanceMap.get(inst); return findAllInRenderedFiberTreeInternal(internalInstance, test); },
function getContextForSubtree( parentComponent: ?React$Component<any, any>, ): Object { if (!parentComponent) { return emptyObject; } const fiber = ReactInstanceMap.get(parentComponent); const parentContext = findCurrentUnmaskedContext(fiber); return isContextProvider(fiber) ? processChildContext(fiber, parentContext) : parentContext; }
function findHostInstance(component: Object): PI | null { const fiber = ReactInstanceMap.get(component); if (fiber === undefined) { if (typeof component.render === 'function') { invariant(false, 'Unable to find node on an unmounted component.'); } else { invariant( false, 'Argument appears to not be a ReactComponent. Keys: %s', Object.keys(component), ); } } const hostFiber = findCurrentHostFiber(fiber); if (hostFiber === null) { return null; } return hostFiber.stateNode; }
function getContextForSubtree( parentComponent: ?React$Component<any, any>, ): Object { if (!parentComponent) { return emptyContextObject; } const fiber = getInstance(parentComponent); const parentContext = findCurrentUnmaskedContext(fiber); if (fiber.tag === ClassComponent) { const Component = fiber.type; if (isLegacyContextProvider(Component)) { return processChildContext(fiber, Component, parentContext); } } return parentContext; }
function getContextForSubtree( parentComponent: ?React$Component<any, any>, ): Object { if (!parentComponent) { return emptyContextObject; } const fiber = ReactInstanceMap.get(parentComponent); const parentContext = findCurrentUnmaskedContext(fiber); if (fiber.tag === ClassComponent) { const Component = fiber.type; if (isLegacyContextProvider(Component)) { return processChildContext(fiber, Component, parentContext); } } else if (fiber.tag === ClassComponentLazy) { const Component = getResultFromResolvedThenable(fiber.type); if (isLegacyContextProvider(Component)) { return processChildContext(fiber, Component, parentContext); } } return parentContext; }
}); } }, findInstance( componentOrElement: Element | ?React$Component<any, any>, ): null | Instance | TextInstance { if (componentOrElement == null) { return null; } // Unsound duck typing. const component = (componentOrElement: any); if (typeof component.id === 'number') { return component; } const inst = ReactInstanceMap.get(component); return inst ? NoopRenderer.findHostInstance(inst) : null; }, flushDeferredPri(timeout: number = Infinity): Array<mixed> { // The legacy version of this function decremented the timeout before // returning the new time. // TODO: Convert tests to use flushUnitsOfWork or flushAndYield instead. const n = timeout / 5 - 1; let values = []; for (const value of flushUnitsOfWork(n)) { values.push(...value); } return values; },
'never access something that requires stale data from the previous ' + 'render, such as refs. Move this logic to componentDidMount and ' + 'componentDidUpdate instead.', getComponentName(owner) || 'A component', ); owner.stateNode._warnedAboutRefsInRender = true; } } if (componentOrElement == null) { return null; } if ((componentOrElement: any).nodeType === ELEMENT_NODE) { return (componentOrElement: any); } var inst = ReactInstanceMap.get(componentOrElement); if (inst) { return DOMRenderer.findHostInstance(inst); } if (typeof componentOrElement.render === 'function') { invariant(false, 'Unable to find node on an unmounted component.'); } else { invariant( false, 'Element appears to be neither ReactComponent nor DOMNode. Keys: %s', Object.keys(componentOrElement), ); } },
export default function( scheduleWork: (fiber: Fiber, expirationTime: ExpirationTime) => void, computeExpirationForFiber: (fiber: Fiber) => ExpirationTime, memoizeProps: (workInProgress: Fiber, props: any) => void, memoizeState: (workInProgress: Fiber, state: any) => void, ) { // Class component state updater const updater = { isMounted, enqueueSetState(instance, partialState, callback) { const fiber = ReactInstanceMap.get(instance); callback = callback === undefined ? null : callback; if (__DEV__) { warnOnInvalidCallback(callback, 'setState'); } const expirationTime = computeExpirationForFiber(fiber); const update = { expirationTime, partialState, callback, isReplace: false, isForced: false, nextCallback: null, next: null, }; insertUpdateIntoFiber(fiber, update); scheduleWork(fiber, expirationTime); }, enqueueReplaceState(instance, state, callback) { const fiber = ReactInstanceMap.get(instance); callback = callback === undefined ? null : callback; if (__DEV__) { warnOnInvalidCallback(callback, 'replaceState'); } const expirationTime = computeExpirationForFiber(fiber); const update = { expirationTime, partialState: state, callback, isReplace: true, isForced: false, nextCallback: null, next: null, }; insertUpdateIntoFiber(fiber, update); scheduleWork(fiber, expirationTime); }, enqueueForceUpdate(instance, callback) { const fiber = ReactInstanceMap.get(instance); callback = callback === undefined ? null : callback; if (__DEV__) { warnOnInvalidCallback(callback, 'forceUpdate'); } const expirationTime = computeExpirationForFiber(fiber); const update = { expirationTime, partialState: null, callback, isReplace: false, isForced: true, nextCallback: null, next: null, }; insertUpdateIntoFiber(fiber, update); scheduleWork(fiber, expirationTime); }, }; 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') { startPhaseTimer(workInProgress, 'shouldComponentUpdate'); const shouldUpdate = instance.shouldComponentUpdate( newProps, newState, newContext, ); stopPhaseTimer(); // Simulate an async bailout/interruption by invoking lifecycle twice. if (debugRenderPhaseSideEffects) { instance.shouldComponentUpdate(newProps, newState, newContext); } 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; } function checkClassInstance(workInProgress: Fiber) { const instance = workInProgress.stateNode; const type = workInProgress.type; if (__DEV__) { const name = getComponentName(workInProgress); const renderPresent = instance.render; if (!renderPresent) { if (type.prototype && typeof type.prototype.render === 'function') { warning( false, '%s(...): No `render` method found on the returned component ' + 'instance: did you accidentally return an object from the constructor?', name, ); } else { warning( false, '%s(...): No `render` method found on the returned component ' + 'instance: you may have forgotten to define `render`.', name, ); } } const noGetInitialStateOnES6 = !instance.getInitialState || instance.getInitialState.isReactClassApproved || instance.state; warning( noGetInitialStateOnES6, 'getInitialState was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Did you mean to define a state property instead?', name, ); const noGetDefaultPropsOnES6 = !instance.getDefaultProps || instance.getDefaultProps.isReactClassApproved; warning( noGetDefaultPropsOnES6, 'getDefaultProps was defined on %s, a plain JavaScript class. ' + 'This is only supported for classes created using React.createClass. ' + 'Use a static property to define defaultProps instead.', name, ); const noInstancePropTypes = !instance.propTypes; warning( noInstancePropTypes, 'propTypes was defined as an instance property on %s. Use a static ' + 'property to define propTypes instead.', name, ); const noInstanceContextTypes = !instance.contextTypes; warning( noInstanceContextTypes, 'contextTypes was defined as an instance property on %s. Use a static ' + 'property to define contextTypes instead.', name, ); const noComponentShouldUpdate = typeof instance.componentShouldUpdate !== 'function'; warning( noComponentShouldUpdate, '%s has a method called ' + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + 'The name is phrased as a question because the function is ' + 'expected to return a value.', name, ); if ( type.prototype && type.prototype.isPureReactComponent && typeof instance.shouldComponentUpdate !== 'undefined' ) { warning( false, '%s has a method called shouldComponentUpdate(). ' + 'shouldComponentUpdate should not be used when extending React.PureComponent. ' + 'Please extend React.Component if shouldComponentUpdate is used.', getComponentName(workInProgress) || 'A pure component', ); } const noComponentDidUnmount = typeof instance.componentDidUnmount !== 'function'; warning( noComponentDidUnmount, '%s has a method called ' + 'componentDidUnmount(). But there is no such lifecycle method. ' + 'Did you mean componentWillUnmount()?', name, ); const noComponentDidReceiveProps = typeof instance.componentDidReceiveProps !== 'function'; warning( noComponentDidReceiveProps, '%s has a method called ' + 'componentDidReceiveProps(). But there is no such lifecycle method. ' + 'If you meant to update the state in response to changing props, ' + 'use componentWillReceiveProps(). If you meant to fetch data or ' + 'run side-effects or mutations after React has updated the UI, use componentDidUpdate().', name, ); const noComponentWillRecieveProps = typeof instance.componentWillRecieveProps !== 'function'; warning( noComponentWillRecieveProps, '%s has a method called ' + 'componentWillRecieveProps(). Did you mean componentWillReceiveProps()?', name, ); const noUnsafeComponentWillRecieveProps = typeof instance.UNSAFE_componentWillRecieveProps !== 'function'; warning( noUnsafeComponentWillRecieveProps, '%s has a method called ' + 'UNSAFE_componentWillRecieveProps(). Did you mean UNSAFE_componentWillReceiveProps()?', name, ); const hasMutatedProps = instance.props !== workInProgress.pendingProps; warning( instance.props === undefined || !hasMutatedProps, '%s(...): When calling super() in `%s`, make sure to pass ' + "up the same props that your component's constructor was passed.", name, name, ); const noInstanceDefaultProps = !instance.defaultProps; warning( noInstanceDefaultProps, 'Setting defaultProps as an instance property on %s is not supported and will be ignored.' + ' Instead, define defaultProps as a static property on %s.', name, name, ); } const state = instance.state; if (state && (typeof state !== 'object' || isArray(state))) { warning( false, '%s.state: must be set to an object or null', getComponentName(workInProgress), ); } if (typeof instance.getChildContext === 'function') { warning( typeof workInProgress.type.childContextTypes === 'object', '%s.getChildContext(): childContextTypes must be defined in order to ' + 'use getChildContext().', getComponentName(workInProgress), ); } } function resetInputPointers(workInProgress: Fiber, instance: any) { instance.props = workInProgress.memoizedProps; instance.state = workInProgress.memoizedState; } function adoptClassInstance(workInProgress: Fiber, instance: any): void { instance.updater = updater; workInProgress.stateNode = instance; // The instance needs access to the fiber so that it can schedule updates ReactInstanceMap.set(instance, workInProgress); if (__DEV__) { instance._reactInternalInstance = fakeInternalInstance; } } function constructClassInstance(workInProgress: Fiber, props: any): any { const ctor = workInProgress.type; const unmaskedContext = getUnmaskedContext(workInProgress); const needsContext = isContextConsumer(workInProgress); const context = needsContext ? getMaskedContext(workInProgress, unmaskedContext) : emptyObject; const instance = new ctor(props, context); const state = instance.state !== null && instance.state !== undefined ? instance.state : null; adoptClassInstance(workInProgress, instance); if (__DEV__) { if ( typeof ctor.getDerivedStateFromProps === 'function' && state === null ) { const componentName = getComponentName(workInProgress) || 'Unknown'; if (!didWarnAboutUninitializedState[componentName]) { warning( false, '%s: Did not properly initialize state during construction. ' + 'Expected state to be an object, but it was %s.', componentName, instance.state === null ? 'null' : 'undefined', ); didWarnAboutUninitializedState[componentName] = true; } } } workInProgress.memoizedState = state; const partialState = callGetDerivedStateFromProps( workInProgress, instance, props, ); if (partialState !== null && partialState !== undefined) { // Render-phase updates (like this) should not be added to the update queue, // So that multiple render passes do not enqueue multiple updates. // Instead, just synchronously merge the returned state into the instance. workInProgress.memoizedState = Object.assign( {}, workInProgress.memoizedState, partialState, ); } // Cache unmasked context so we can avoid recreating masked context unless necessary. // ReactFiberContext usually updates this cache but can't for newly-created instances. if (needsContext) { cacheContext(workInProgress, unmaskedContext, context); } return instance; } function callComponentWillMount(workInProgress, instance) { startPhaseTimer(workInProgress, 'componentWillMount'); const oldState = instance.state; if (typeof instance.componentWillMount === 'function') { if (__DEV__) { if (warnAboutDeprecatedLifecycles) { const componentName = getComponentName(workInProgress) || 'Component'; if (!didWarnAboutLegacyWillMount[componentName]) { warning( false, '%s: componentWillMount() is deprecated and will be ' + 'removed in the next major version. Read about the motivations ' + 'behind this change: ' + 'https://fb.me/react-async-component-lifecycle-hooks' + '\n\n' + 'As a temporary workaround, you can rename to ' + 'UNSAFE_componentWillMount instead.', componentName, ); didWarnAboutLegacyWillMount[componentName] = true; } } } instance.componentWillMount(); } else { instance.UNSAFE_componentWillMount(); } stopPhaseTimer(); if (oldState !== instance.state) { if (__DEV__) { warning( false, '%s.componentWillMount(): Assigning directly to this.state is ' + "deprecated (except inside a component's " + 'constructor). Use setState instead.', getComponentName(workInProgress), ); } updater.enqueueReplaceState(instance, instance.state, null); } } function callComponentWillReceiveProps( workInProgress, instance, newProps, newContext, ) { const oldState = instance.state; if (typeof instance.componentWillReceiveProps === 'function') { if (__DEV__) { if (warnAboutDeprecatedLifecycles) { const componentName = getComponentName(workInProgress) || 'Component'; if (!didWarnAboutLegacyWillReceiveProps[componentName]) { warning( false, '%s: componentWillReceiveProps() is deprecated and ' + 'will be removed in the next major version. Use ' + 'static getDerivedStateFromProps() instead. Read about the ' + 'motivations behind this change: ' + 'https://fb.me/react-async-component-lifecycle-hooks' + '\n\n' + 'As a temporary workaround, you can rename to ' + 'UNSAFE_componentWillReceiveProps instead.', componentName, ); didWarnAboutLegacyWillReceiveProps[componentName] = true; } } } startPhaseTimer(workInProgress, 'componentWillReceiveProps'); instance.componentWillReceiveProps(newProps, newContext); stopPhaseTimer(); } else { startPhaseTimer(workInProgress, 'componentWillReceiveProps'); instance.UNSAFE_componentWillReceiveProps(newProps, newContext); stopPhaseTimer(); // Simulate an async bailout/interruption by invoking lifecycle twice. if (debugRenderPhaseSideEffects) { instance.UNSAFE_componentWillReceiveProps(newProps, newContext); } } if (instance.state !== oldState) { if (__DEV__) { const componentName = getComponentName(workInProgress) || 'Component'; if (!didWarnAboutStateAssignmentForComponent[componentName]) { warning( false, '%s.componentWillReceiveProps(): Assigning directly to ' + "this.state is deprecated (except inside a component's " + 'constructor). Use setState instead.', componentName, ); didWarnAboutStateAssignmentForComponent[componentName] = true; } } updater.enqueueReplaceState(instance, instance.state, null); } } function callGetDerivedStateFromProps( workInProgress: Fiber, instance: any, props: any, ) { const {type} = workInProgress; if (typeof type.getDerivedStateFromProps === 'function') { if (__DEV__) { if ( typeof instance.componentWillReceiveProps === 'function' || typeof instance.UNSAFE_componentWillReceiveProps === 'function' ) { const componentName = getComponentName(workInProgress) || 'Unknown'; if (!didWarnAboutWillReceivePropsAndDerivedState[componentName]) { warning( false, '%s: Defines both componentWillReceiveProps() and static ' + 'getDerivedStateFromProps() methods. We recommend using ' + 'only getDerivedStateFromProps().', componentName, ); didWarnAboutWillReceivePropsAndDerivedState[componentName] = true; } } } const partialState = type.getDerivedStateFromProps.call( null, props, workInProgress.memoizedState, ); if (__DEV__) { if (partialState === undefined) { const componentName = getComponentName(workInProgress) || 'Unknown'; if (!didWarnAboutUndefinedDerivedState[componentName]) { warning( false, '%s.getDerivedStateFromProps(): A valid state object (or null) must be returned. ' + 'You have returned undefined.', componentName, ); didWarnAboutUndefinedDerivedState[componentName] = componentName; } } } return partialState; } } // Invokes the mount life-cycles on a previously never rendered instance. function mountClassInstance( workInProgress: Fiber, renderExpirationTime: ExpirationTime, ): void { const current = workInProgress.alternate; if (__DEV__) { checkClassInstance(workInProgress); } const instance = workInProgress.stateNode; const props = workInProgress.pendingProps; const unmaskedContext = getUnmaskedContext(workInProgress); instance.props = props; instance.state = workInProgress.memoizedState; instance.refs = emptyObject; instance.context = getMaskedContext(workInProgress, unmaskedContext); if ( enableAsyncSubtreeAPI && workInProgress.type != null && workInProgress.type.prototype != null && workInProgress.type.prototype.unstable_isAsyncReactComponent === true ) { workInProgress.internalContextTag |= AsyncUpdates; } if ( typeof instance.UNSAFE_componentWillMount === 'function' || typeof instance.componentWillMount === 'function' ) { callComponentWillMount(workInProgress, instance); // If we had additional state updates during this life-cycle, let's // process them now. const updateQueue = workInProgress.updateQueue; if (updateQueue !== null) { instance.state = processUpdateQueue( current, workInProgress, updateQueue, instance, props, renderExpirationTime, ); } } if (typeof instance.componentDidMount === 'function') { workInProgress.effectTag |= Update; } } // 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 = processUpdateQueue( // 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 = processUpdateQueue( // 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, renderExpirationTime: ExpirationTime, ): boolean { const instance = workInProgress.stateNode; resetInputPointers(workInProgress, instance); const oldProps = workInProgress.memoizedProps; const newProps = workInProgress.pendingProps; 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.UNSAFE_componentWillReceiveProps === 'function' || typeof instance.componentWillReceiveProps === 'function') && (oldProps !== newProps || oldContext !== newContext) ) { callComponentWillReceiveProps( workInProgress, instance, newProps, newContext, ); } let partialState; if (oldProps !== newProps) { partialState = callGetDerivedStateFromProps( workInProgress, instance, newProps, ); } // 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 = processUpdateQueue( current, workInProgress, workInProgress.updateQueue, instance, newProps, renderExpirationTime, ); } else { newState = oldState; } if (partialState !== null && partialState !== undefined) { // Render-phase updates (like this) should not be added to the update queue, // So that multiple render passes do not enqueue multiple updates. // Instead, just synchronously merge the returned state into the instance. newState = newState === null || newState === undefined ? partialState : Object.assign({}, newState, partialState); } 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.UNSAFE_componentWillUpdate === 'function' || typeof instance.componentWillUpdate === 'function' ) { if (typeof instance.componentWillUpdate === 'function') { if (__DEV__) { if (warnAboutDeprecatedLifecycles) { const componentName = getComponentName(workInProgress) || 'Component'; if (!didWarnAboutLegacyWillUpdate[componentName]) { warning( false, '%s: componentWillUpdate() is deprecated and will be ' + 'removed in the next major version. Read about the motivations ' + 'behind this change: ' + 'https://fb.me/react-async-component-lifecycle-hooks' + '\n\n' + 'As a temporary workaround, you can rename to ' + 'UNSAFE_componentWillUpdate instead.', componentName, ); didWarnAboutLegacyWillUpdate[componentName] = true; } } } startPhaseTimer(workInProgress, 'componentWillUpdate'); instance.componentWillUpdate(newProps, newState, newContext); stopPhaseTimer(); } else { startPhaseTimer(workInProgress, 'componentWillUpdate'); instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); stopPhaseTimer(); // Simulate an async bailout/interruption by invoking lifecycle twice. if (debugRenderPhaseSideEffects) { instance.UNSAFE_componentWillUpdate(newProps, newState, newContext); } } } 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; } return { adoptClassInstance, callGetDerivedStateFromProps, constructClassInstance, mountClassInstance, // resumeMountClassInstance, updateClassInstance, }; }
? prevState : Object.assign({}, prevState, partialState); workInProgress.memoizedState = memoizedState; // Once the update queue is empty, persist the derived state onto the // base state. const updateQueue = workInProgress.updateQueue; if (updateQueue !== null && workInProgress.expirationTime === NoWork) { updateQueue.baseState = memoizedState; } } const classComponentUpdater = { isMounted, enqueueSetState(inst, payload, callback) { const fiber = getInstance(inst); const currentTime = requestCurrentTime(); const expirationTime = computeExpirationForFiber(currentTime, fiber); const update = createUpdate(expirationTime); update.payload = payload; if (callback !== undefined && callback !== null) { if (__DEV__) { warnOnInvalidCallback(callback, 'setState'); } update.callback = callback; } flushPassiveEffects(); enqueueUpdate(fiber, update); scheduleWork(fiber, expirationTime);
? prevState : Object.assign({}, prevState, partialState); workInProgress.memoizedState = memoizedState; // Once the update queue is empty, persist the derived state onto the // base state. const updateQueue = workInProgress.updateQueue; if (updateQueue !== null && workInProgress.expirationTime === NoWork) { updateQueue.baseState = memoizedState; } } const classComponentUpdater = { isMounted, enqueueSetState(inst, payload, callback) { const fiber = ReactInstanceMap.get(inst); const currentTime = requestCurrentTime(); const expirationTime = computeExpirationForFiber(currentTime, fiber); const update = createUpdate(expirationTime); update.payload = payload; if (callback !== undefined && callback !== null) { if (__DEV__) { warnOnInvalidCallback(callback, 'setState'); } update.callback = callback; } enqueueUpdate(fiber, update); scheduleWork(fiber, expirationTime); },