Когда я впервые начал изучать React.js, больше всего меня смущало время жизни любого данного компонента: когда компонент создается React, когда он заменяет существующий и как я могу узнать какая «версия» компонента работает в любой момент времени?

На самом деле это просто, но это сложно описать словами. Также сложно осмыслить изображения, и я думаю, что по этим двум причинам я какое-то время не находил нужного результата. Так что, я думаю, было бы проще, если бы мы использовали псевдокод!

Когда вы впервые render компонент, React берет ваш компонент и вызывает на нем рендеринг. Для функций это просто означает возврат функции. Для классов это означает создание его временного экземпляра и вызов метода render:

function render(component) {
  let view;
  if (typeof component === 'function') {
    view = component();
  }
  else {
    const instance = new component();
    view = instance.render();
  }
  // recursively render(view.children)
}

Поскольку наши представления иерархичны, React отображает их рекурсивно. Отображение рекурсии здесь мало что добавляет, но важно отметить, что каждый отдельный компонент на основе классов в этом дереве рендеринга, независимо от того, насколько глубоко в дереве, только что был создан, создавая временный новый экземпляр.

Когда вы впервые выполняете рендеринг в DOM, эти временные экземпляры стали официальными экземплярами, и React хранит их в памяти для вас. Поздравляем, ваши экземпляры никуда не денутся! Ну, ненадолго.

Каждый раз, когда компонент на основе классов вызывает setState, React запускает процесс согласования. Вы можете подробно изучить алгоритм согласования, но для этой статьи все, что вам нужно знать, это то, что он должен проверять, не изменилось ли что-нибудь само по себе или его дочерним элементам. Но как это узнать? Его нужно перерисовать!

class Component {
  // ...
  __stateChanged() {
    const a = this.existingView();
    const b = render(this);
    // ... diff ...
  }
}

Итак, теперь b содержит содержимое совершенно нового дерева рендеринга, включая новые экземпляры всех компонентов на основе классов на этом уровне в дереве и ниже!

Это означает, что если у вас есть такой класс:

class MyComponent {
  constructor() {
    this.foo = GetSomeData(); // bad!
  }
}

тогда React вызовет new MyComponent(), затем вызовет myComponent.render() и возможно выбросит экземпляр по завершении, если ничего не изменилось.

В этом случае это означает, что вы можете увидеть избыточные вызовы GetSomeData! Вот почему вы должны помещать такие вещи в componentDidMount, потому что именно в этот момент вы точно знаете, что ваш компонент является «официальным».

Если что-то приведет к тому, что ваш компонент получит новые свойства, он все равно сохранит старый экземпляр компонента и просто обновит свои свойства новыми реквизитами:

class Component {
  __maybeUpdate(temporaryInstance) {
    if (differentProps(this.props, temporaryInstance.props)) {
      const prevProps = this.props;
      this.props = temporaryInstance.props;
      this.componentDidUpdate(prevProps);
    }
  }
}

Теперь React сохранил ваш «официальный» экземпляр компонента на основе классов и обновил его, добавив в него новое состояние и новые свойства! Старый экземпляр снова выбрасывается, так как он использовался только для процесса согласования.

Единственный раз, когда компонент становится «неофициальным», - это когда он отключается. И единственный раз, когда он отключается, - это когда ничего похожего больше нет в этом месте в дереве представления после того, как он снова отрисовывается. Это часть выверки, поэтому подробные сведения см. В вышеупомянутом документе.

Итак, подведем итог:

  1. Компоненты React постоянно создаются для различий и проверок, поэтому не полагайтесь на свои конструкторы ни в чем серьезном или постоянном.
  2. Пока он смонтирован, это «официальная» версия, которая остается в памяти, начиная с componentDidMount.
  3. Новые версии свойств извлекаются из временных экземпляров компонента на основе классов и перезаписывают свойства «официального» экземпляра.
  4. Единственный раз, когда компонент перестает быть «официальным», - это когда вы перестаете видеть его на экране, и в этот момент вызывается componentWillUnmount.

Я надеюсь, что это поможет избавиться от мистификации времени жизни компонентов React на основе классов.