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;
  }
Exemple #6
0
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.',
        );
      }
    }
  }
Exemple #9
0
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;
  }