Компоненты позволяют разделить пользовательский интерфейс на самостоятельные, многоразовые фрагменты и подумать о каждой части отдельно. React.Component обеспечивается React.

React.Component является абстрактным базовым классом, поэтому редко имеет смысл обратиться к нему React.Component напрямую. Вместо этого вы обычно подклассифицируете его и определите по крайней мере render() метод.

Обычно вы определяете компонент React как обычный класс JavaScript:

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Если вы еще не используете ES6, вы можете использовать create-react-class модуль.

Обратите внимание: что не рекомендуется создавать собственные классы базовых компонентов . Повторное использование кода в основном достигается с помощью композиции, а не наследования в React. 

Жизненный цикл компонента

Каждый компонент имеет несколько «методов жизненного цикла», которые вы можете переопределить для запуска кода в определенное время в процессе. Методы с префиксом will называются прямо перед тем, как что-то происходит, а методы с префиксом did называются сразу после того, как что-то происходит.

Mounting

Эти методы вызывают, когда экземпляр компонента создается и вставляется в DOM:

  • constructor()
  • static getDerivedStateFromProps()
  • componentWillMount() / UNSAFE_componentWillMount()
  • render()
  • componentDidMount()

Updating

Обновление может быть вызвано изменениями в реквизитах или состоянии. Эти методы вызывается, когда компонент повторно отображается:

  • componentWillReceiveProps() / UNSAFE_componentWillReceiveProps()
  • static getDerivedStateFromProps()
  • shouldComponentUpdate()
  • componentWillUpdate() / UNSAFE_componentWillUpdate()
  • render()
  • getSnapshotBeforeUpdate()
  • componentDidUpdate()

Unmounting

Этот метод вызывается, когда компонент удаляется из DOM:

  • componentWillUnmount()

Error Handling

Этот метод вызывается при возникновении ошибки во время рендеринга, в методе жизненного цикла или в конструкторе любого дочернего компонента.

  • componentDidCatch()

Другие API

Каждый компонент также предоставляет некоторые другие API:

  • setState()
  • forceUpdate()

Свойства класса

  • defaultProps
  • displayName

Свойства экземпляра

  • props
  • state

Reference

render()

render()

При вызове, он должен изучить this.propsи this.state и вернуть один из следующих типов:

  • React elements. Обычно создается через JSX. Элемент может быть либо представлением нативного компонента DOM ( <div />), либо определяемого пользователем составного компонента ( <MyComponent />).
  • String and numbers.  Они отображаются как текстовые узлы в DOM.
  • Portals. Создано с ReactDOM.createPortal.
  • null. Не делает ничего.
  • Booleans. Ничего не делайте. (В основном существует поддержка return test && <Child /> шаблона, где test имеет значение boolean).

При возвращении null или false, ReactDOM.findDOMNode(this) вернется null.

render() функция должна быть чистой, а это означает , что она не изменяет состояние компонента, она возвращает тот же результат , каждый раз , когда она вызывается, и он непосредственно не взаимодействует с браузером. Если вам нужно взаимодействовать с браузером, componentDidMount() вместо этого выполните свою работу или другие методы жизненного цикла. Сохранение render() чистых компонентов делает их более легкими.

Заметка

render() не будет вызываться, если shouldComponentUpdate() возвращает false.

Фрагменты

Вы также можете вернуть несколько элементов из render() массива:

render() {
  return [
    <li key="A">First item</li>,
    <li key="B">Second item</li>,
    <li key="C">Third item</li>,
  ];
}

Заметка:

Не забудьте добавить ключи к элементам во фрагменте, чтобы избежать предупреждения ключа.

Начиная с React 16.2.0 , то же самое можно выполнить с помощью фрагментов , для которых не требуются ключи для статических элементов:

render() {
  return (
    <React.Fragment>
      <li>First item</li>
      <li>Second item</li>
      <li>Third item</li>
    </React.Fragment>
  );
}

constructor()

constructor(props)

Конструктор для компонента React вызывается до его установки. При реализации конструктора для React.Component подкласса вы должны вызывать super(props) перед любым другим утверждением. В противном случае конструктор this.props не будет определен, что может привести к ошибкам.

Избегайте введения каких-либо побочных эффектов или подписки в конструкторе. Для этих случаев использования используйте componentDidMount() вместо этого.

Конструктор - это правильное место для инициализации состояния. Для этого просто назначьте объект this.state; не пытайтесь вызвать setState() из конструктора. Конструктор также часто используется для привязки обработчиков событий к экземпляру класса.

Если вы не инициализируете состояние и не связываете методы, вам не нужно реализовывать конструктор для вашего компонента React.

В редких случаях нормально инициализировать состояние на основе реквизита. Это эффективно «pops» реквизита и устанавливает состояние с исходными реквизитами. Вот пример действительного React.Component конструктора подкласса:

constructor(props) {
  super(props);
  this.state = {
    color: props.initialColor
  };
}

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

Если вы используете «fork» реквизиты, используя их для состояния, вы также можете реализовать, getDerivedStateFromProps() чтобы поддерживать состояние с ними в актуальном состоянии. Но подъем состояния часто бывает проще и менее подвержен ошибкам.

static getDerivedStateFromProps()

static getDerivedStateFromProps(nextProps, prevState)

getDerivedStateFromProps вызывается после создания экземпляра компонента, а также при получении новых реквизитов. Он должен вернуть объект для обновления состояния или null, чтобы указать, что новые реквизиты не требуют каких-либо обновлений состояния.

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

Вызов this.setState() обычно не срабатывает getDerivedStateFromProps().

UNSAFE_componentWillMount()

UNSAFE_componentWillMount()

UNSAFE_componentWillMount() вызывается непосредственно перед установкой. Он вызывается раньше render(), поэтому вызов setState() синхронно в этом методе не вызовет дополнительный рендеринг. Как правило, мы рекомендуем использовать constructor() вместо этого для инициализации.

Избегайте введения каких-либо побочных эффектов или подписки в этом методе. Для этих случаев использования используйте componentDidMount() вместо этого.

Это единственный крючок жизненного цикла, вызванный рендерингом сервера.

Заметка

Этот жизненный цикл был ранее назван componentWillMount. Это имя будет продолжать работать до версии 17. Используйте rename-unsafe-lifecyclescodemod для автоматического обновления ваших компонентов.

componentDidMount()

componentDidMount()

componentDidMount() вызывается сразу после установки компонента. Инициализация, требующая узлов DOM, должна идти здесь. Если вам нужно загружать данные с удаленной конечной точки, это хорошее место для создания экземпляра сетевого запроса.

Этот метод является хорошим местом для настройки подписки. Если вы это сделаете, не забудьте отказаться от подписки componentWillUnmount().

Вызов setState() этого метода вызовет дополнительный рендеринг, но это произойдет до того, как браузер обновит экран. Это гарантирует, что, хотя render() в этом случае вызов будет вызываться дважды, пользователь не увидит промежуточное состояние. Используйте этот шаблон с осторожностью, поскольку он часто вызывает проблемы с производительностью. Однако это может быть необходимо для таких случаев, как модалы и всплывающие подсказки, когда вам нужно измерить узел DOM, прежде чем отображать что-то, зависящее от его размера или положения.

UNSAFE_componentWillReceiveProps()

UNSAFE_componentWillReceiveProps(nextProps)

Заметка:

Рекомендуется использовать статический getDerivedStateFromProps жизненный цикл вместо него UNSAFE_componentWillReceiveProps.

UNSAFE_componentWillReceiveProps() вызывается, прежде чем монтируемый компонент получит новые реквизиты. Если вам необходимо обновить состояние в ответ на проп изменения (например, чтобы сбросить его), вы можете сравнить this.propsи nextProps и выполнять переходы состояний , используя this.setState() в этом методе.

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

Реакт не звонит UNSAFE_componentWillReceiveProps() с начальным реквизитом во время монтажа . Он вызывает этот метод только в том случае, если некоторые реквизиты компонента могут обновляться. Вызов this.setState() обычно не срабатывает UNSAFE_componentWillReceiveProps().

Заметка:

Этот жизненный цикл был ранее назван componentWillReceiveProps. Это имя будет продолжать работать до версии 17. Используйте rename-unsafe-lifecyclescodemod для автоматического обновления ваших компонентов.

shouldComponentUpdate()

shouldComponentUpdate(nextProps, nextState)

Используйте, shouldComponentUpdate() чтобы позволить React знать, не влияет ли на результат компонента текущее изменение состояния или реквизита. Поведение по умолчанию заключается в повторном рендеринге при каждом изменении состояния, и в подавляющем большинстве случаев вы должны полагаться на поведение по умолчанию.

shouldComponentUpdate() вызывается перед рендерингом при получении новых реквизитов или состояний. По умолчанию true. Этот метод не вызывается для начальной визуализации или когда forceUpdate() используется.

Возврат false не предотвращает повторное рендеринг дочерних компонентов при изменении их состояния.

В настоящее время, если shouldComponentUpdate() возвращается false, то UNSAFE_componentWillUpdate(), render() и componentDidUpdate() не будет вызван. Обратите внимание, что в будущем React может рассматриваться shouldComponentUpdate() как подсказка, а не строгая директива, и возвращение false может по-прежнему приводить к повторному рендерингу компонента.

Если вы определите, что определенный компонент медленный после профилирования, вы можете изменить его на наследование, из React.PureComponentкоторого реализуется shouldComponentUpdate() с неглубокой поддержкой и сравнением состояний. Если вы уверены, что хотите написать его вручную, вы можете сравнить this.props с ним nextProps и this.state с ним nextState и вернуться, false чтобы сообщить React, обновление может быть пропущено.

Мы не рекомендуем делать глубокие проверки равенства или использования JSON.stringify() в shouldComponentUpdate(). Это очень неэффективно и будет наносить ущерб производительности.

UNSAFE_componentWillUpdate()

UNSAFE_componentWillUpdate(nextProps, nextState)

UNSAFE_componentWillUpdate() вызывается непосредственно перед рендерингом при получении новых реквизитов или состояний. Используйте это как возможность выполнить подготовку до того, как произойдет обновление. Этот метод не вызывается для первоначального рендеринга.

Обратите внимание, что вы не можете позвонить this.setState() здесь; и вы не должны делать что-либо еще (например, отправить действие Redux), которое будет инициировать обновление компонента React перед UNSAFE_componentWillUpdate() возвратом.

Если вам нужно обновить stateв ответ на propsизменения, используйте getDerivedStateFromProps() вместо этого.

Заметка:

Этот жизненный цикл был ранее назван componentWillUpdate. Это имя будет продолжать работать до версии 17. Используйте rename-unsafe-lifecyclescodemod для автоматического обновления ваших компонентов.

Заметка:

UNSAFE_componentWillUpdate() не будет вызываться, если shouldComponentUpdate() возвращает false.

getSnapshotBeforeUpdate()

getSnapshotBeforeUpdate() вызывается непосредственно перед тем, как последний обработанный вывод будет выполнен, например, для DOM. Он позволяет вашему компоненту фиксировать текущие значения (например, положение прокрутки), прежде чем они будут потенциально изменены. Любое значение, возвращаемое этим жизненным циклом, будет передано как параметр to componentDidUpdate().

Например:

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // Are we adding new items to the list?
    // Capture the scroll position so we can adjust scroll later.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // If we have a snapshot value, we've just added new items.
    // Adjust scroll so these new items don't push the old ones out of view.
    // (snapshot here is the value returned from getSnapshotBeforeUpdate)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

В приведенных выше примерах важно прочитать scrollHeight свойство, getSnapshotBeforeUpdate а не componentWillUpdate поддерживать асинхронный рендеринг. При асинхронном рендеринге могут возникать задержки между «жизненными циклами» визуализации (например, componentWillUpdate и render) и «фиксацией» фазовых жизненных циклов (например, getSnapshotBeforeUpdate и componentDidUpdate). Если пользователь делает что-то вроде изменения размера браузера в течение этого времени, scrollHeight значение, считанное с, componentWillUpdate будет устаревшим.

componentDidUpdate()

componentDidUpdate(prevProps, prevState, snapshot)

componentDidUpdate() вызывается сразу после обновления. Этот метод не вызывается для первоначального рендеринга.

Используйте это как возможность работать с DOM при обновлении компонента. Это также хорошее место для выполнения сетевых запросов, если вы сравниваете текущие реквизиты с предыдущими реквизитами (например, сетевой запрос может не понадобиться, если реквизит не изменился).

Если ваш компонент реализует getSnapshotBeforeUpdate() жизненный цикл, возвращаемое им значение будет передано в качестве третьего параметра «моментального снимка» componentDidUpdate(). (В противном случае этот параметр будет неопределенным.)

Заметка:

componentDidUpdate() не будет вызываться, если shouldComponentUpdate() возвращает false.

componentWillUnmount()

componentWillUnmount()

componentWillUnmount() вызывается непосредственно перед размонтированием и уничтожением компонента. Выполните любую необходимую очистку в этом методе, такую ​​как недействительность таймеров, отмена сетевых запросов или очистка любых подписей, которые были созданы componentDidMount().

componentDidCatch()

componentDidCatch(error, info)

Границы ошибок - это компоненты React, которые улавливают ошибки JavaScript в любом месте их дочернего дерева компонентов, регистрируют эти ошибки и отображают резервный интерфейс вместо разбитого дерева компонентов. Границы ошибок ломают ошибки при рендеринге, в методах жизненного цикла и в конструкторах всего дерева под ними.

Компонент класса становится границей ошибки, если он определяет этот метод жизненного цикла. Вызов setState()в нем позволяет зафиксировать необработанную ошибку JavaScript в приведенном ниже дереве и отобразить резервный интерфейс. Используйте только границы ошибок для восстановления от неожиданных исключений; не пытайтесь использовать их для управления потоком.

Заметка:

Границы ошибок только ломают ошибки в компонентах под ними в дереве. Граница ошибки не может поймать ошибку внутри себя.

setState()

setState(updater[, callback])

setState() enqueues изменяет состояние компонента и сообщает React, что этот компонент и его дочерние элементы должны быть повторно отображены с обновленным состоянием. Это основной метод, который вы используете для обновления пользовательского интерфейса в ответ на обработчики событий и ответы сервера.

Подумайте setState() как запрос, а не немедленную команду для обновления компонента. Для лучшей воспринимаемой производительности React может задержать ее, а затем обновить несколько компонентов за один проход. Реакция не гарантирует немедленного применения изменений состояния.

setState() не всегда сразу обновляет компонент. Он может перезагружать или откладывать обновление до следующего. Это делает чтение this.state сразу после вызова setState() потенциальной ловушки. Вместо этого используйте componentDidUpdate или setState обратный вызов ( setState(updater, callback)), каждый из которых может быть запущен после применения обновления. Если вам нужно установить состояние на основе предыдущего состояния, прочтите приведенный updater ниже аргумент.

setState() всегда приведет к повторной обработке, если не будет shouldComponentUpdate() возвращено false. Если используются изменяемые объекты, и логика условного воспроизведения не может быть реализована shouldComponentUpdate(), вызов setState() только тогда, когда новое состояние отличается от предыдущего состояния, позволит избежать ненужных повторных рендерингов.

Первый аргумент - это updaterфункция с сигнатурой:

(prevState, props) => stateChange

prevState является ссылкой на предыдущее состояние. Он не должен быть непосредственно мутирован. Вместо этого изменения должны быть представлены путем создания нового объекта на основе ввода из prevState и props. Например, предположим, что мы хотели бы увеличить значение в состоянии props.step:

this.setState((prevState, props) => {
  return {counter: prevState.counter + props.step};
});

Оба prevState и props полученные функцией обновления гарантированно будут обновлены. Выходной файл обновления сглаживается неглубоко prevState.

Второй параметр to setState()- необязательная функция обратного вызова, которая будет выполнена один раз, setState будет завершена, и компонент будет повторно отображен. Обычно мы рекомендуем использовать componentDidUpdate() для такой логики.

Вы можете опционально передать объект в качестве первого аргумента setState() вместо функции:

setState(stateChange[, callback])

Это выполняет мелкое слияние stateChange в новое состояние, например, чтобы настроить количество товаров в корзине:

this.setState({quantity: 2})

Эта форма setState() также асинхронна, и несколько вызовов в течение одного цикла могут быть объединены вместе. Например, если вы пытаетесь увеличить количество элементов более одного раза в одном цикле, это приведет к эквиваленту:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ...
)

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

this.setState((prevState) => {
  return {quantity: prevState.quantity + 1};
});

forceUpdate()

component.forceUpdate(callback)

По умолчанию, когда состояние вашего компонента или реквизита изменяется, ваш компонент будет повторно отображать. Если ваш render() метод зависит от некоторых других данных, вы можете сказать React, что компонент нуждается в повторном рендеринге, вызвав forceUpdate().

Вызов forceUpdate() вызовет render() вызов компонента, пропущенный shouldComponentUpdate(). Это вызовет обычные методы жизненного цикла для дочерних компонентов, включая shouldComponentUpdate() метод каждого дочернего элемента. React по-прежнему будет обновлять DOM только в случае изменения разметки.

Как правило, вы должны стараться избегать всех видов использования forceUpdate() и только для чтения с this.props и this.state в render().

Свойства класса

defaultProps

defaultProps может быть определено как свойство самого класса компонента, чтобы установить реквизиты по умолчанию для класса. Это используется для неопределенных реквизитов, но не для нулевого реквизита. Например:

class CustomButton extends React.Component {
  // ...
}

CustomButton.defaultProps = {
  color: 'blue'
};

Если props.color это не предусмотрено, оно будет установлено по умолчанию 'blue':

render() {
    return <CustomButton /> ; // props.color will be set to blue
  }

Если props.color установлено значение null, оно останется равным null:

 render() {
    return <CustomButton color={null} /> ; // props.color will remain null
  }

displayName

displayName строка используется в отладочных сообщений. Обычно вам не нужно явно указывать его, поскольку он выводится из имени функции или класса, который определяет компонент. Возможно, вы захотите установить его явно, если хотите отобразить другое имя для целей отладки или когда вы создаете компонент более высокого порядка.

Свойства экземпляра

props

this.props содержит реквизиты, которые были определены вызывающим элементом этого компонента.
В частности, this.props.children это специальная поддержка, обычно определяемая дочерними тегами в выражении JSX, а не в самом теге.

state

Состояние содержит данные, специфичные для этого компонента, которые могут меняться со временем. Состояние определено пользователем, и оно должно быть простым объектом JavaScript.

Если какое-либо значение не используется для рендеринга или потока данных (например, идентификатор таймера), вам не нужно вставлять его в состояние. Такие значения могут быть определены как поля экземпляра компонента.

Никогда не мутируйте this.state напрямую, так как вызов setState() впоследствии может заменить мутацию, которую вы сделали. Обращайся так, this.state как будто это было неизменным.