Графический setState

React.js

ИсследованиеsetStateЭтот вопрос возникает из-за сомнения: при использовании reduxdispatchОдинaction, почему это может привести к обновлению представления?

Первое предположениеstoreПосле изменения куда-то позвонил редуксsetState, который сообщает реагировать.

Я посмотрел на код и обнаружил, что это действительно так, позвонивdispatch actionвызоветonStateChangeфункция (эта функция находится вconnectбыл зарегистрирован наstore,storeодеялоreducerЗапускается после модификации),onStateChangeфункция определения необходимостиshouldComponentUpdateзатем выполнитьthis.setState({})для запуска реагирующих обновлений.

Итак, возникает вопрос:

  1. ЗачемsetStateМожно сделать обновление вида, как это происходит пошаговоvirtualDOMа затем визуализировалось
  2. setStateПочему производительность иногда асинхронна, а иногда синхронна?
  3. Почему в функции жизненного циклаwillReceivePropsмогуsetStateа такжеwillUpdateнет?

После обводки процесса мы получаем следующий рисунок.На рисунке функция, которую нужно выполнить, стоит перед двоеточием каждого блока процесса:

Кратко опишу процесс:

  • setStateПосле входящегоstateпоставить в очередьqueue,enqueueUpdateметод будет основан наisBatchingUpdateОтметить битовое суждение, если компонент в настоящее время обновляется, текущий компонент будет размещен непосредственноdirtyComponentsмассив, иначеisBatchingUpdateУстановите значение true и включите «массовое обновление (batchedUpdates)" транзакции (transaction).

Проще говоря, так называемаяTransactionэто то, что нужно будет реализоватьmethodиспользоватьwrapperупакованы, а затем переданыTransactionкоторый предоставилperformметод выполняется. пока вperformперед этим выполнить всеwrapperсерединаinitialize 方法;performПосле завершения (т.methodпосле выполнения), а затем выполнить всеcloseметод. Группаinitializeа такжеcloseметод, называемыйwrapper, Transactionподдерживает несколькоwrapperналожение.

После того, как транзакция открыта, она будет выполняться последовательноinitialize、perform、closeметод. можно увидеть,batchedUpdatesсуществуетperformэтап будет выполнен сноваenqueueUpdateметод, посколькуisBatchingUpdateуже верно, поэтому поместит текущий компонент вdirtyComponents. ключcloseстадия, еслиdirtyComponentsЕсли он пустой, значит обновление не требуется, иначе он начнет обновляться и включитсяflushBatchedUpdatesдела.

  • flushBatchedUpdatesсуществуетperformэтап будетdirtyComponentsкомпоненты в父 > 子Порядок компонентов вызывает метод обновления, и компоненты будут выполняться последовательно при их обновлении:
willReceiveProps -> 将 queue 中缓存的 state 与缓存的 state 合并 -> shouldComponentUpdate。

Если определено, что требуется обновление, выполнитеrenderспособ получить новыйreactElement, сравните его с предыдущимreactElementПросто выполните diff и передайте результаты diff (удалить, переместить и т. д.) черезsetInnerHTMLПросто подождите, пока метод инкапсуляции обновит представление, и детали можно увидеть на рисунке.

  • flushBatchedUpdatesсуществуетcloseэтап будет проверен сноваdirtyComponentsИзменилась ли длина, если изменилась, значит, есть новаяdirtyComponent, нужно сделать это сноваflushBatchedUpdates.

НаполнятьupdateComponentКод:

// 更新组件
updateComponent: function(transaction, prevParentElement, nextParentElement) {
  var prevContext = this.context;
  var prevProps = this.props;
  var nextContext = prevContext;
  var nextProps = prevProps;

  if (prevParentElement !== nextParentElement) {
    nextContext = this._processContext(nextParentElement._context);
    nextProps = this._processProps(nextParentElement.props);
    // 当前状态为 RECEIVING_PROPS
    this._compositeLifeCycleState = CompositeLifeCycle.RECEIVING_PROPS;

    // 如果存在 componentWillReceiveProps,则执行
    if (this.componentWillReceiveProps) {
      this.componentWillReceiveProps(nextProps, nextContext);
    }
  }

  // 设置状态为 null,更新 state
  this._compositeLifeCycleState = null;
  var nextState = this._pendingState || this.state;
  this._pendingState = null;
  var shouldUpdate =
    this._pendingForceUpdate ||
    !this.shouldComponentUpdate ||
    this.shouldComponentUpdate(nextProps, nextState, nextContext);
  if (!shouldUpdate) {
    // 如果确定组件不更新,仍然要设置 props 和 state
    this._currentElement = nextParentElement;
    this.props = nextProps;
    this.state = nextState;
    this.context = nextContext;
    this._owner = nextParentElement._owner;
    return;
  }
  this._pendingForceUpdate = false;

  ......

  // 如果存在 componentWillUpdate,则触发
  if (this.componentWillUpdate) {
    this.componentWillUpdate(nextProps, nextState, nextContext);
  }

  // render 递归渲染
  var nextMarkup = this._renderedComponent.mountComponent(
    thisID,
    transaction,
    this._mountDepth + 1
  );

  // 如果存在 componentDidUpdate,则触发
  if (this.componentDidUpdate) {
    transaction.getReactMountReady().enqueue(
      this.componentDidUpdate.bind(this, prevProps, prevState, prevContext),
      this
    );
  }
},

Весь процесс может ответить на некоторые из предыдущих сомнений:

  1. ЗачемsetStateзатем журнал, иногдаstateНе сразу, а иногда?

в жизненном циклеsetStateв большомtransaction, В настоящее времяisBatchingUpdateдляtrue,воплощать в жизньsetStateСделает толькоdirtyComponentsМассив толкает текущий компонент без дальнейшей обработки. В это время журнал смотрит на негоstateВсе еще никаких изменений. тогда как если вне транзакции, например.setTimeoutвнутриsetState,В настоящее времяisBatchingUpdateдляfalse, он будет выполнен непосредственно до измененияstate, значит лог выходит в это времяstateпоменяли сразу. следовательноСинхронность setState не гарантируется, а не то, что она должна быть асинхронной..

2. Все в одномtranaction, почему вwillReceivePropsтакже можетsetState, пока вshouldComponentUpdateа такжеwillUpdateкогдаsetStateНе приведет ли это к бесконечному циклу в браузере?

Внутри компонента есть флаг_compositeLifeCycleStateПредставляет текущее состояние жизненного цикла вwillReceivePropsранее был установлен наRECEIVING_PROPS,существуетwillReceivePropsустановлен на ноль после выполнения, в то время какperformUpdateIfNecessaryВ текущем состоянии функцииMOUNTINGилиRECEIVING_PROPSне будет продолжать звонитьupdateComponentфункция.

performUpdateIfNecessary: function(transaction) {
  var compositeLifeCycleState = this._compositeLifeCycleState;
  //  ■■■■■■■■重点■■■■■■■■■■■■
  // 当状态为 MOUNTING 或 RECEIVING_PROPS 时,则不更新
  if (compositeLifeCycleState === CompositeLifeCycle.MOUNTING ||
      compositeLifeCycleState === CompositeLifeCycle.RECEIVING_PROPS) {
    return;
  }

  var prevElement = this._currentElement;
  var nextElement = prevElement;
  if (this._pendingElement != null) {
    nextElement = this._pendingElement;
    this._pendingElement = null;
  }

  // 调用 updateComponent
  this.updateComponent(
    transaction,
    prevElement,
    nextElement
  );
}

Таким образом, вwillReceivePropsВремяsetStateиз-за_compositeLifeCycleStateужеRECEIVING_PROPS, не запускает новыйupdateComponent, пока вwillUpdateкогда_compositeLifeCycleStateбыл установлен обратно в ноль, поэтому это приведет к следующемуupdateComponent, а затем снова запускать каждый жизненный цикл компонента, конечно, он неизбежно будет выполнятьсяwillUpdate, таким образом входя в бесконечный цикл.