Spec-Zone.ru › React 18

Компонент

Опасность

Рекомендуется определять компоненты как функции, а не классы. См. как мигрировать.

Component — базовый класс для React-компонентов, определённых как JavaScript-классы. Классовые компоненты всё ещё поддерживаются React, но мы не рекомендуем использовать их в новом коде.

class Greeting extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}
  • Справочник
    • Component
    • context
    • props
    • refs
    • state
    • constructor(props)
    • componentDidCatch(error, info)
    • componentDidMount()
    • componentDidUpdate(prevProps, prevState, snapshot?)
    • componentWillMount()
    • componentWillReceiveProps(nextProps)
    • componentWillUpdate(nextProps, nextState)
    • componentWillUnmount()
    • forceUpdate(callback?)
    • getChildContext()
    • getSnapshotBeforeUpdate(prevProps, prevState)
    • render()
    • setState(nextState, callback?)
    • shouldComponentUpdate(nextProps, nextState, nextContext)
    • UNSAFE_componentWillMount()
    • UNSAFE_componentWillReceiveProps(nextProps, nextContext)
    • UNSAFE_componentWillUpdate(nextProps, nextState)
    • static childContextTypes
    • static contextTypes
    • static contextType
    • static defaultProps
    • static propTypes
    • static getDerivedStateFromError(error)
    • static getDerivedStateFromProps(props, state)
  • Использование
    • Определение класса-компонента
    • Добавление состояния в компонент-класс
    • Добавление методов жизненного цикла в компонент-класс
    • Перехват ошибок рендеринга с помощью границы ошибок
  • Альтернативы
    • Миграция простого компонента из класса в функцию
    • Миграция компонента со состоянием из класса в функцию
    • Миграция компонента с методами жизненного цикла из класса в функцию
    • Миграция компонента с контекстом из класса в функцию

Справочник

Component

Чтобы определить React-компонент как класс, расширьте встроенный Component класс и определите метод render:

import { Component } from 'react';

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

Требуется только метод render, другие методы являются необязательными.

См. больше примеров ниже.


context

Контекст компонента-класса доступен как this.context. Он доступен только если вы укажете какой контекст вы хотите получить, используя static contextType (современный) или static contextTypes (устаревший).

Компонент-класс может читать только один контекст за раз.

class Button extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {this.props.children}
      </button>
    );
  }
}

Примечание

Чтение this.context в компонентах-классах эквивалентно useContext в функциональных компонентах.

См. как мигрировать.


props

Переданные свойства компонента-класса доступны как this.props.

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

<Greeting name="Taylor" />

Примечание

Чтение this.props в компонентах-классах эквивалентно объявлению свойств в функциональных компонентах.

См. как мигрировать.


refs

Устаревшее

Этот API будет удалён в будущей основной версии React. Используйте createRef вместо этого.

Позволяет получить доступ к устаревшим строковым ссылкам для этого компонента.


state

Состояние компонента-класса доступно как this.state. Поле state должно быть объектом. Не изменяйте состояние напрямую. Если вы хотите изменить состояние, вызовите setState с новым состоянием.

class Counter extends Component {
  state = {
    age: 42,
  };

  handleAgeChange = () => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <button onClick={this.handleAgeChange}>
        Increment age
        </button>
        <p>You are {this.state.age}.</p>
      </>
    );
  }
}

Примечание

Определение state в компонентах-классах эквивалентно вызову useState в функциональных компонентах.

См. как мигрировать.


constructor(props)

Конструктор выполняется до того, как ваш компонент-класс подключается (добавляется на экран). Обычно конструктор используется только для двух целей в React. Он позволяет вам объявить состояние и связать методы вашего класса с экземпляром класса:

class Counter extends Component {
  constructor(props) {
    super(props);
    this.state = { counter: 0 };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // ...
  }

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

class Counter extends Component {
  state = { counter: 0 };

  handleClick = () => {
    // ...
  }

Конструктор не должен содержать побочных эффектов или подписок.

Параметры

  • props: начальные свойства компонента.

Возвращаемое значение

constructor не должно возвращать ничего.

Примечания

  • Не выполняйте побочных эффектов или подписок в конструкторе. Вместо этого используйте componentDidMount для этого.

  • Внутри конструктора необходимо вызвать super(props) перед любой другой инструкцией. Если этого не сделать, this.props будет undefined во время выполнения конструктора, что может быть запутанно и привести к ошибкам.

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

  • Когда вы используете серверный рендеринг, конструктор будет выполняться и на сервере, за которым последует метод render. Однако методы жизненного цикла, такие как componentDidMount или componentWillUnmount , не будут выполняться на сервере.

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

Примечание

Точного эквивалента constructor в функциональных компонентах нет. Для объявления состояния в функциональном компоненте вызовите useState. Чтобы избежать повторного расчёта начального состояния, передайте функцию в useState.


componentDidCatch(error, info)

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

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

См. пример.

Параметры

  • error: выброшенная ошибка. На практике, это обычно экземпляр Error, но это не гарантируется, так как JavaScript позволяет throw любое значение, включая строки или даже null.

  • info: объект, содержащий дополнительную информацию об ошибке. Его поле componentStack содержит трассировку стека с компонентом, выбросившим ошибку, а также имена и места расположения всех его родительских компонентов. В продакшене имена компонентов будут сжаты. Если вы настроите отчёт об ошибках в продакшене, вы можете декодировать стек компонентов, используя sourcemaps так же, как вы это делаете для обычных JavaScript-стеков ошибок.

Возвращаемое значение

componentDidCatch не должно возвращать ничего.

Примечания

  • В прошлом, было принято вызывать setState внутри componentDidCatch для обновления пользовательского интерфейса и отображения сообщения об ошибке по умолчанию. Это устарело, в пользу определения static getDerivedStateFromError.

  • Производственные и эталонные сборки React немного отличаются в том, как componentDidCatch обрабатывает ошибки. В режиме разработки ошибки передаются в window, что означает, что любые window.onerror или window.addEventListener('error', callback) перехватывают ошибки, которые были пойманы componentDidCatch. В производстве, наоборот, ошибки не передаются, что означает, что любой обработчик ошибок предка получит только те ошибки, которые не были явно пойманы componentDidCatch.

Примечание

Прямого эквивалента componentDidCatch в компонентах функций пока нет. Если вы хотите избежать создания компонентов класса, напишите один компонент ErrorBoundary как выше и используйте его во всем приложении. Кроме того, вы можете использовать пакет react-error-boundary, который делает это за вас.


componentDidMount()

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

Если вы реализуете componentDidMount, вам обычно необходимо реализовать другие методы жизненного цикла, чтобы избежать ошибок. Например, если componentDidMount считывает некоторое состояние или свойства, вам также нужно реализовать componentDidUpdate для обработки их изменений и componentWillUnmount для очистки всего, что componentDidMount делало.

class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  // ...
}

См. дополнительные примеры.

Параметры

componentDidMount не принимает никаких параметров.

Возвращает

componentDidMount ничего не должен возвращать.

Ограничения

  • Когда Режим строгости включен, в режиме разработки React вызовет componentDidMount, а затем немедленно вызовет componentWillUnmount, а затем вызовет componentDidMount снова. Это помогает заметить, если вы забыли реализовать componentWillUnmount или если его логика полностью не «отражает» то, что componentDidMount делает.

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

Примечание

Для многих случаев использования определение componentDidMount, componentDidUpdate, и componentWillUnmount вместе в компонентах класса эквивалентно вызову useEffect в компонентах функций. В редких случаях, когда важно, чтобы код выполнялся до отрисовки браузером, useLayoutEffect является более подходящим аналогом.

См. как мигрировать.


componentDidUpdate(prevProps, prevState, snapshot?)

Если вы определите метод componentDidUpdate, React вызовет его сразу после того, как ваш компонент будет повторно отрисован с обновленными свойствами или состоянием. Этот метод не вызывается для начального рендеринга.

Вы можете использовать его для манипулирования DOM после обновления. Это также общее место для выполнения сетевых запросов, если вы сравниваете текущие свойства с предыдущими свойствами (например, сетевой запрос может не потребоваться, если свойства не изменились). Обычно вы будете использовать его вместе с componentDidMount и componentWillUnmount:

class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  // ...
}

См. дополнительные примеры.

Параметры

  • prevProps: Свойства до обновления. Сравните prevProps с this.props, чтобы определить, что изменилось.

  • prevState: Состояние до обновления. Сравните prevState с this.state, чтобы определить, что изменилось.

  • snapshot: Если вы реализовали getSnapshotBeforeUpdate, snapshot будет содержать значение, которое вы вернули из этого метода. В противном случае оно будет undefined.

Возвращает

componentDidUpdate ничего не должен возвращать.

Ограничения

  • componentDidUpdate не будет вызван, если shouldComponentUpdate определен и возвращает false.

  • Логика внутри componentDidUpdate обычно должна быть заключена в условия сравнения this.props с prevProps, и this.state с prevState. В противном случае существует риск создания бесконечных циклов.

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

Примечание

Для многих случаев использования определение componentDidMount, componentDidUpdate, и componentWillUnmount вместе в компонентах класса эквивалентно вызову useEffect в компонентах функций. В редких случаях, когда важно, чтобы код выполнялся до отрисовки браузером, useLayoutEffect является более подходящим аналогом.

См. как мигрировать.


componentWillMount()

Устарело

Этот API был переименован из componentWillMount в UNSAFE_componentWillMount. Старое имя устарело. В будущей основной версии React будет работать только новое имя.

Запустите rename-unsafe-lifecycles кодмод для автоматического обновления ваших компонентов.


componentWillReceiveProps(nextProps)

Устарело

Этот API был переименован из componentWillReceiveProps в UNSAFE_componentWillReceiveProps. Старое имя устарело. В будущей основной версии React будет работать только новое имя.

Запустите rename-unsafe-lifecycles кодмод для автоматического обновления ваших компонентов.


componentWillUpdate(nextProps, nextState)

Устарело

Этот API был переименован из componentWillUpdate в UNSAFE_componentWillUpdate. Старое имя устарело. В будущей основной версии React будет работать только новое имя.

Запустите rename-unsafe-lifecycles кодмод для автоматического обновления ваших компонентов.


componentWillUnmount()

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

Логика внутри componentWillUnmount должна «отражать» логику внутри componentDidMount. Например, если componentDidMount настраивает подписку, componentWillUnmount должна очистить эту подписку. Если логика очистки в вашем componentWillUnmount читает некоторые свойства или состояние, вам обычно также потребуется реализовать componentDidUpdate для очистки ресурсов (таких как подписки), соответствующих старым свойствам и состоянию.

class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  // ...
}

См. дополнительные примеры.

Параметры

componentWillUnmount не принимает никаких параметров.

Возвращает

componentWillUnmount ничего не должен возвращать.

Ограничения

  • Когда Режим строгости включен, в режиме разработки React вызовет componentDidMount, а затем немедленно вызовет componentWillUnmount, а затем вызовет componentDidMount снова. Это помогает заметить, если вы забыли реализовать componentWillUnmount или если его логика полностью не «отражает» то, что componentDidMount делает.

Примечание

Для многих случаев использования определение componentDidMount, componentDidUpdate, и componentWillUnmount вместе в компонентах класса эквивалентно вызову useEffect в компонентах функций. В редких случаях, когда важно, чтобы код выполнялся до отрисовки браузером, useLayoutEffect является более подходящим аналогом.

См. как мигрировать.


forceUpdate(callback?)

Принудительно перерисовывает компонент.

Обычно это не нужно. Если метод render вашего компонента только считывает данные из this.props, this.state или this.context, он будет перерисовываться автоматически, когда вы вызовете setState внутри компонента или одного из его родителей. Однако, если метод вашего компонента render считывает данные напрямую из внешнего источника, вам нужно указать React, как обновить пользовательский интерфейс при изменении этого источника данных. Для этого и предназначен forceUpdate.

Старайтесь избегать использования forceUpdate и считывайте данные только из this.props и this.state в render.

Параметры

  • необязательно callback Если указано, React вызовет предоставленный вами callback после завершения обновления.

Возвращаемое значение

forceUpdate ничего не возвращает.

Примечания

  • Если вы вызываете forceUpdate, React перерисует компонент без вызова shouldComponentUpdate.

Примечание

Чтение данных из внешнего источника и принудительное перерисовывание компонентов класса в ответ на их изменения с помощью forceUpdate было заменено на useSyncExternalStore в функциональных компонентах.


getChildContext()

Устаревшее

Этот API будет удален в будущей основной версии React. Используйте Context.Provider вместо этого.

Позволяет указать значения для старого контекста, предоставляемого этим компонентом.


getSnapshotBeforeUpdate(prevProps, prevState)

Если вы реализуете getSnapshotBeforeUpdate, React вызовет его непосредственно перед обновлением DOM. Это позволяет вашему компоненту получить некоторые данные из DOM (например, позицию скролла) перед возможным изменением. Любое значение, возвращенное этим методом жизненного цикла, будет передано в качестве параметра в 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. Небезопасно читать его в render, UNSAFE_componentWillReceiveProps или UNSAFE_componentWillUpdate, так как может возникнуть задержка между вызовом этих методов и обновлением DOM React.

Параметры

  • prevProps: Свойства перед обновлением. Сравните prevProps с this.props, чтобы определить, что изменилось.

  • prevState: Состояние перед обновлением. Сравните prevState с this.state, чтобы определить, что изменилось.

Возвращаемое значение

Вы должны вернуть значение снимка любого типа, которое вам нужно, или null. Возвращенное вами значение будет передано в качестве третьего аргумента в componentDidUpdate.

Примечания

  • getSnapshotBeforeUpdate не будет вызван, если shouldComponentUpdate определён и возвращает false.

Примечание

В данный момент эквивалента getSnapshotBeforeUpdate для функциональных компонентов не существует. Такой случай использования встречается редко, но если вам это нужно, пока придётся использовать компонент класса.


render()

Метод render — единственный обязательный метод в компоненте класса.

Метод render должен указать, что вы хотите отобразить на экране, например:

import { Component } from 'react';

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

React может вызвать render в любой момент, поэтому не следует полагаться на конкретное время его выполнения. Обычно метод render должен возвращать фрагмент JSX, но поддерживаются и некоторые другие типы возвращаемых значений (например, строки). Для вычисления возвращаемого JSX, метод render может считывать this.props, this.state и this.context.

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

Параметры

render не принимает никаких параметров.

Возвращаемое значение

render может возвращать любой допустимый узел React. Это включает элементы React, такие как <div />, строки, числа, порталы, пустые узлы (null, undefined, true, и false), и массивы узлов React.

Примечания

  • render должен быть написан в виде чистой функции от свойств, состояния и контекста. Он не должен иметь побочных эффектов.

  • render не будет вызван, если shouldComponentUpdate определён и возвращает false.

  • При включенном режиме Strict Mode, React дважды вызовет render в режиме разработки, а затем удалит один из результатов. Это помогает обнаружить случайные побочные эффекты, которые нужно перенести из метода render.

  • Нет однозначного соответствия между вызовом render и последующим вызовом componentDidMount или componentDidUpdate. Некоторые результаты вызова render могут быть отброшены React, когда это выгодно.


setState(nextState, callback?)

Вызовите setState для обновления состояния вашего компонента React.

class Form extends Component {
  state = {
    name: 'Taylor',
  };

  handleNameChange = (e) => {
    const newName = e.target.value;
    this.setState({
      name: newName
    });
  }

  render() {
    return (
      <>
        <input value={this.state.name} onChange={this.handleNameChange} />
        <p>Hello, {this.state.name}.</p>
      </>
    );
  }
}

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

Опасность

Вызов setState не изменяет текущее состояние в уже выполняемом коде:

function handleClick() {
  console.log(this.state.name); // "Taylor"
  this.setState({
    name: 'Robin'
  });
  console.log(this.state.name); // Still "Taylor"!
}

Он только повлияет на то, что this.state вернет начиная с следующего перерисовки.

Вы также можете передать функцию в setState. Это позволяет обновлять состояние на основе предыдущего состояния:

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

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

Параметры

  • nextState: Объект или функция.

    • Если вы передаете объект в качестве nextState, он будет поверхностно объединен в this.state.
    • Если вы передаете функцию в качестве nextState, она будет обрабатываться как функция обновления. Она должна быть чистой, принимать текущее состояние и свойства в качестве аргументов и возвращать объект, который поверхностно объединяется с this.state. React поместит вашу функцию обновления в очередь и перерисует ваш компонент. Во время следующего перерисовки React вычислит следующее состояние, применяя все queued обновления к предыдущему состоянию.
  • необязательно callback: Если указано, React вызовет предоставленную вами callback после завершения обновления.

Возвращаемое значение

setState ничего не возвращает.

Примечания

  • Подумайте о setState как о запросе, а не об императивном обновлении состояния компонента. Когда несколько компонентов обновляют своё состояние в ответ на событие, React объединит их обновления и перерисует их вместе в одном проходе в конце события. В редких случаях, когда вам нужно принудительно применить конкретное обновление состояния синхронно, вы можете обернуть его в flushSync, но это может навредить производительности.

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

Примечание

Вызов setState в компонентах класса аналогичен вызову функции set в функциональных компонентах.

Посмотрите как переносить.


shouldComponentUpdate(nextProps, nextState, nextContext)

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

Если вы уверены, что хотите написать его вручную, вы можете сравнить this.props с nextProps и this.state с nextState и вернуть false, чтобы сказать React, что обновление можно пропустить.

class Rectangle extends Component {
  state = {
    isHovered: false
  };

  shouldComponentUpdate(nextProps, nextState) {
    if (
      nextProps.position.x === this.props.position.x &&
      nextProps.position.y === this.props.position.y &&
      nextProps.size.width === this.props.size.width &&
      nextProps.size.height === this.props.size.height &&
      nextState.isHovered === this.state.isHovered
    ) {
      // Nothing has changed, so a re-render is unnecessary
      return false;
    }
    return true;
  }

  // ...
}

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

Параметры

  • nextProps: Следующие свойства, которые компонент собирается отобразить. Сравните nextProps с this.props, чтобы определить, что изменилось.
  • nextState: Следующее состояние, с которым собирается отобразиться компонент. Сравните nextState с this.state, чтобы определить, что изменилось.
  • nextContext: Следующий контекст, с которым собирается отобразиться компонент. Сравните nextContext с this.context, чтобы определить, что изменилось. Доступно только если вы указали static contextType (современный) или static contextTypes (устаревший).

Возвращаемое значение

Возвратите true, если вы хотите, чтобы компонент перерисовывался. Это стандартное поведение.

Возвратите false, чтобы сообщить React, что перерисовку можно пропустить.

Примечания

  • Этот метод существует только в качестве оптимизации производительности. Если ваш компонент сломался без него, исправьте это в первую очередь.

  • Рассмотрите использование PureComponent вместо написания shouldComponentUpdate вручную. PureComponent поверхностно сравнивает свойства и состояние, и уменьшает вероятность пропуска необходимых обновлений.

  • Мы не рекомендуем выполнять глубокие проверки равенства или использовать JSON.stringify в shouldComponentUpdate. Это делает производительность непредсказуемой и зависимой от структуры данных каждого свойства и состояния. В лучшем случае, вы рискуете ввести многосекундные задержки в своем приложении, а в худшем – рискнете его сломать.

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

  • Возвращение false не гарантирует, что компонент не будет перерисован. React будет использовать возвращаемое значение как подсказку, но все же может выбрать перерисовку вашего компонента, если это имеет смысл по другим причинам.

Примечание

Оптимизация компонентов класса с shouldComponentUpdate похожа на оптимизацию функциональных компонентов с memo. Функциональные компоненты также предлагают более тонкую оптимизацию с useMemo.


UNSAFE_componentWillMount()

Если вы определите UNSAFE_componentWillMount, React вызовет его сразу после constructor. Он существует только по историческим причинам и не должен использоваться в новом коде. Вместо этого используйте один из альтернатив:

  • Для инициализации состояния, объявите state как поле класса или установите this.state внутри constructor.
  • Если вам нужно выполнить побочное действие или настроить подписку, переместите эту логику в componentDidMount вместо этого.

См. примеры миграции от небезопасных жизненных циклов.

Параметры

UNSAFE_componentWillMount не принимает никаких параметров.

Возвращаемое значение

UNSAFE_componentWillMount не должно возвращать ничего.

Примечания

  • UNSAFE_componentWillMount не будет вызван, если компонент реализует static getDerivedStateFromProps или getSnapshotBeforeUpdate.

  • Несмотря на свое название, UNSAFE_componentWillMount не гарантирует, что компонент будет смонтирован, если ваше приложение использует современные функции React, такие как Suspense. Если попытка рендеринга приостановлена (например, потому что код какого-то дочернего компонента еще не загружен), React удалит текущее дерево и попытается воссоздать компонент заново во время следующей попытки. Вот почему этот метод «небезопасен». Код, который полагается на монтирование (например, добавление подписки), должен находиться в componentDidMount.

  • UNSAFE_componentWillMount — единственный метод жизненного цикла, который выполняется во время серверного рендеринга. Для всех практических целей он идентичен constructor, поэтому для этого типа логики следует использовать constructor.

Примечание

Вызов setState внутри UNSAFE_componentWillMount в компоненте класса эквивалентен передаче этого состояния в качестве начального состояния к useState в функциональном компоненте.


UNSAFE_componentWillReceiveProps(nextProps, nextContext)

Если вы определите UNSAFE_componentWillReceiveProps, React вызовет его, когда компонент получит новые свойства. Он существует только по историческим причинам и не должен использоваться в новом коде. Вместо этого используйте один из вариантов:

  • Если вам нужно выполнить побочное действие (например, получить данные, запустить анимацию или перезапустить подписку) в ответ на изменения свойств, переместите эту логику в componentDidUpdate вместо этого.
  • Если вам нужно избежать повторного вычисления некоторых данных только при изменении свойства, используйте помощник мемоизации вместо этого.
  • Если вам нужно «сбросить» некоторое состояние при изменении свойства, рассмотрите возможность сделать компонент полностью контролируемым или полностью неконтролируемым с ключом вместо этого.
  • Если вам нужно «настроить» некоторое состояние при изменении свойства, проверьте, можете ли вы вычислить всю необходимую информацию из свойств в процессе рендеринга. Если нет, используйте static getDerivedStateFromProps вместо этого.

См. примеры миграции от небезопасных жизненных циклов.

Параметры

  • nextProps: Следующие свойства, которые компонент собирается получить от родительского компонента. Сравните nextProps с this.props, чтобы определить, что изменилось.
  • nextContext: Следующий контекст, который компонент собирается получить от ближайшего провайдера. Сравните nextContext с this.context, чтобы определить, что изменилось. Доступно только если вы указали static contextType (современный) или static contextTypes (устаревший).

Возвращаемое значение

UNSAFE_componentWillReceiveProps не должно возвращать ничего.

Примечания

  • UNSAFE_componentWillReceiveProps не будет вызван, если компонент реализует static getDerivedStateFromProps или getSnapshotBeforeUpdate.

  • Несмотря на свое название, UNSAFE_componentWillReceiveProps не гарантирует, что компонент получит эти свойства, если ваше приложение использует современные функции React, такие как Suspense. Если попытка рендеринга приостановлена (например, потому что код какого-то дочернего компонента еще не загружен), React удалит текущее дерево и попытается воссоздать компонент заново во время следующей попытки. К моменту следующей попытки рендеринга свойства могут быть другими. Вот почему этот метод «небезопасен». Код, который должен выполняться только для подтвержденных обновлений (например, сброс подписки), должен находиться в componentDidUpdate.

  • UNSAFE_componentWillReceiveProps не означает, что компонент получил другие свойства, чем в прошлый раз. Вам необходимо сравнить nextProps и this.props самостоятельно, чтобы проверить, изменилось ли что-то.

  • React не вызывает UNSAFE_componentWillReceiveProps с начальными свойствами во время монтирования. Он вызывает этот метод только если какие-то свойства компонента собираются обновиться. Например, вызов setState обычно не вызывает UNSAFE_componentWillReceiveProps внутри того же компонента.

Примечание

Вызов setState внутри UNSAFE_componentWillReceiveProps в компоненте класса эквивалентен вызову функции set из useState во время рендеринга в функциональном компоненте.


UNSAFE_componentWillUpdate(nextProps, nextState)

Если вы определите UNSAFE_componentWillUpdate, React вызовет его перед рендерингом с новыми свойствами или состоянием. Он существует только по историческим причинам и не должен использоваться в новом коде. Вместо этого используйте один из вариантов:

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

См. примеры миграции от небезопасных жизненных циклов.

Параметры

  • nextProps: Следующие свойства, которые компонент собирается отобразить. Сравните nextProps с this.props, чтобы определить, что изменилось.
  • nextState: Следующее состояние, с которым собирается отобразиться компонент. Сравните nextState с this.state, чтобы определить, что изменилось.

Возвращаемое значение

UNSAFE_componentWillUpdate не должно возвращать ничего.

Примечания

  • UNSAFE_componentWillUpdate не будет вызван, если shouldComponentUpdate определён и возвращает false.

  • UNSAFE_componentWillUpdate не будет вызван, если компонент реализует static getDerivedStateFromProps или getSnapshotBeforeUpdate.

  • Не допускается вызывать setState (или любой метод, приводящий к вызову setState, например, отправка действия Redux) во время componentWillUpdate.

  • Несмотря на название, UNSAFE_componentWillUpdate не гарантирует, что компонент обновится, если ваше приложение использует современные возможности React, такие как Suspense. Если попытка отрисовки приостановлена (например, потому что код для какого-то дочернего компонента ещё не загружен), React удалит текущую версию дерева и попытается создать компонент заново при следующей попытке. К моменту следующей попытки отрисовки свойства и состояние могут измениться. Именно поэтому этот метод является «небезопасным». Код, который должен выполняться только для подтверждённых обновлений (например, сброс подписки), должен находиться в componentDidUpdate.

  • UNSAFE_componentWillUpdate не означает, что компонент получил другие свойства или состояние, чем в прошлый раз. Вам необходимо самостоятельно сравнить nextProps со this.props и nextState с this.state для проверки изменений.

  • React не вызывает UNSAFE_componentWillUpdate с начальными свойствами и состоянием во время монтирования.

Примечание

В функциональных компонентах нет прямого эквивалента UNSAFE_componentWillUpdate.


static childContextTypes

Устаревшее

Этот API будет удалён в будущей основной версии React. Используйте static contextType вместо этого.

Позволяет указать, какой старый контекст предоставляется этим компонентом.


static contextTypes

Устаревшее

Этот API будет удалён в будущей основной версии React. Используйте static contextType вместо этого.

Позволяет указать, какой старый контекст потребляется этим компонентом.


static contextType

Если вы хотите прочитать this.context из своего компонента класса, вы должны указать, какой контекст ему необходимо прочитать. Контекст, который вы указываете как static contextType , должен быть значением, ранее созданным с помощью createContext.

class Button extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {this.props.children}
      </button>
    );
  }
}

Примечание

Чтение this.context в компонентах класса эквивалентно useContext в функциональных компонентах.

См. как мигрировать.


static defaultProps

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

Например, вот как вы можете задать значение по умолчанию для свойства color равное 'blue':

class Button extends Component {
  static defaultProps = {
    color: 'blue'
  };

  render() {
    return <button className={this.props.color}>click me</button>;
  }
}

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

<>
  {/* this.props.color is "blue" */}
  <Button />

  {/* this.props.color is "blue" */}
  <Button color={undefined} />

  {/* this.props.color is null */}
  <Button color={null} />

  {/* this.props.color is "red" */}
  <Button color="red" />
</>

Примечание

Определение defaultProps в компонентах класса аналогично использованию значений по умолчанию в функциональных компонентах.


static propTypes

Вы можете определить static propTypes вместе с библиотекой prop-types для объявления типов свойств, принимаемых вашим компонентом. Эти типы будут проверяться во время отрисовки и только в режиме разработки.

import PropTypes from 'prop-types';

class Greeting extends React.Component {
  static propTypes = {
    name: PropTypes.string
  };

  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}

Примечание

Рекомендуется использовать TypeScript вместо проверки типов свойств во время выполнения.


static getDerivedStateFromError(error)

Если вы определите static getDerivedStateFromError, React вызовет его, когда дочерний компонент (включая удалённые дочерние компоненты) выбросит ошибку во время отрисовки. Это позволяет отобразить сообщение об ошибке вместо очистки пользовательского интерфейса.

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

См. пример.

Параметры

  • error: Выброшенная ошибка. На практике, обычно это будет экземпляр Error, но это не гарантируется, так как JavaScript позволяет throw любое значение, включая строки или даже null.

Возвращаемое значение

static getDerivedStateFromError должен вернуть состояние, указывающее компоненту на отображение сообщения об ошибке.

Ограничения

  • static getDerivedStateFromError должен быть чистой функцией. Если вы хотите выполнить побочное действие (например, вызвать службу аналитики), вам нужно также реализовать componentDidCatch.

Примечание

Для static getDerivedStateFromError в функциональных компонентах пока нет прямого эквивалента. Если вы хотите избежать создания компонентов класса, напишите один компонент ErrorBoundary как выше и используйте его во всём приложении. Или используйте пакет react-error-boundary, который это делает.


static getDerivedStateFromProps(props, state)

Если вы определите static getDerivedStateFromProps, React вызовет его прямо перед вызовом render, как при первоначальном монтировании, так и при последующих обновлениях. Он должен вернуть объект для обновления состояния или null для того, чтобы ничего не обновлять.

Этот метод существует для редких случаев, когда состояние зависит от изменений свойств со временем. Например, этот Form компонент сбрасывает состояние email при изменении свойства userID:

class Form extends Component {
  state = {
    email: this.props.defaultEmail,
    prevUserID: this.props.userID
  };

  static getDerivedStateFromProps(props, state) {
    // Any time the current user changes,
    // Reset any parts of state that are tied to that user.
    // In this simple example, that's just the email.
    if (props.userID !== state.prevUserID) {
      return {
        prevUserID: props.userID,
        email: props.defaultEmail
      };
    }
    return null;
  }

  // ...
}

Обратите внимание, что этот шаблон требует сохранения предыдущего значения свойства (например, userID) в состоянии (например, prevUserID).

Опасность

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

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

Параметры

  • props: Следующие свойства, с которыми компонент собирается отобразиться.
  • state: Следующее состояние, с которым компонент собирается отобразиться.

Возвращаемое значение

static getDerivedStateFromProps должен вернуть объект для обновления состояния или null для того, чтобы ничего не обновлять.

Ограничения

  • Этот метод вызывается при каждом отрисовке, независимо от причины. Это отличается от UNSAFE_componentWillReceiveProps, который вызывается только тогда, когда родитель вызывает перерисовку, а не в результате локального setState.

  • Этот метод не имеет доступа к экземпляру компонента. Если вам нужно, вы можете повторно использовать код между static getDerivedStateFromProps и другими методами класса, вынеся чистые функции свойств и состояния компонента за пределы определения класса.

Примечание

Реализация static getDerivedStateFromProps в компоненте класса эквивалентна вызову функции set из useState во время отрисовки в функциональном компоненте.


Использование

Определение компонента класса

Чтобы определить компонент React как класс, расширьте встроенный класс Component и определите метод render:

import { Component } from 'react';

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

React вызовет ваш метод render всякий раз, когда ему нужно определить, что отображать на экране. Обычно вы возвращаете JSX из него. Ваш метод render должен быть чистой функцией: он должен только вычислять JSX.

Аналогично компонентам-функциям, компонент-класс может получать информацию через атрибуты от родительского компонента. Однако синтаксис для чтения атрибутов отличается. Например, если родительский компонент отображает <Greeting name="Taylor" />, то вы можете прочитать атрибут name из this.props, как this.props.name:

import { Component } from 'react';

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

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

Обратите внимание, что хуки (функции, начинающиеся с use, например, useState) не поддерживаются внутри компонентов-классов.

Опасность

Рекомендуется определять компоненты как функции, а не как классы. См. как мигрировать.


Добавление состояния в компонент-класс

Чтобы добавить состояние в класс, назначьте объект свойству, называемому state. Для обновления состояния вызовите this.setState.

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = () => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

Опасность

Рекомендуется определять компоненты как функции, а не как классы. См. как мигрировать.


Добавление методов жизненного цикла в компонент-класс

Вы можете определить несколько специальных методов в вашем классе.

Если вы определите метод componentDidMount, React вызовет его, когда ваш компонент будет добавлен (прикреплен) на экран. React вызовет componentDidUpdate после повторного рендеринга вашего компонента из-за изменения свойств или состояния. React вызовет componentWillUnmount после того, как ваш компонент будет удален (откреплен) с экрана.

Если вы реализуете componentDidMount, вам обычно нужно реализовать все три жизненных цикла, чтобы избежать ошибок. Например, если componentDidMount считывает некоторое состояние или свойства, вам также необходимо реализовать componentDidUpdate для обработки их изменений и componentWillUnmount для очистки того, что componentDidMount делал.

Например, этот ChatRoom компонент синхронизирует соединение чата со свойствами и состоянием:

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Welcome to the {this.props.roomId} room!</h1>
      </>
    );
  }
}

Обратите внимание, что в режиме разработки, когда включен Жесткий режим, React вызовет componentDidMount, немедленно вызовет componentWillUnmount, а затем снова вызовет componentDidMount. Это помогает выявить, если вы забыли реализовать componentWillUnmount или если его логика не полностью «отражает» то, что делает componentDidMount.

Опасность

Рекомендуется определять компоненты как функции, а не как классы. См. как мигрировать.


Обработка ошибок рендеринга с помощью обработчика ошибок

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

Для реализации компонента обработчика ошибок вам необходимо предоставить static getDerivedStateFromError, который позволяет обновить состояние в ответ на ошибку и отобразить пользователю сообщение об ошибке. Вы также можете необязательно реализовать componentDidCatch, чтобы добавить дополнительную логику, например, для регистрации ошибки в службе аналитики.

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }

  static getDerivedStateFromError(error) {
    // Update state so the next render will show the fallback UI.
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    // Example "componentStack":
    //   in ComponentThatThrows (created by App)
    //   in ErrorBoundary (created by App)
    //   in div (created by App)
    //   in App
    logErrorToMyService(error, info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return this.props.fallback;
    }

    return this.props.children;
  }
}

Затем вы можете обернуть часть вашего дерева компонентов им:

<ErrorBoundary fallback={<p>Something went wrong</p>}>
  <Profile />
</ErrorBoundary>

Если Profile или его дочерний компонент выбросит ошибку, ErrorBoundary «поймает» эту ошибку, отобразит резервное пользовательское интерфейс с сообщением об ошибке, которое вы предоставили, и отправит отчет об ошибке в вашу службу отслеживания ошибок.

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

Примечание

В настоящее время нет способа написать обработчик ошибок как компонент-функцию. Однако вам не нужно самостоятельно писать класс обработчика ошибок. Например, вы можете использовать react-error-boundary вместо этого.


Альтернативы

Миграция простого компонента из класса в функцию

Обычно вы будете определять компоненты как функции вместо этого.

Например, предположим, что вы конвертируете этот Greeting компонент-класс в функцию:

import { Component } from 'react';

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

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}

Определите функцию с именем Greeting. Это то, куда вы переместите тело вашей render функции.

function Greeting() {
  // ... move the code from the render method here ...
}

Вместо this.props.name, определите атрибут name используя синтаксис деструктуризации и читайте его напрямую:

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

Вот полный пример:

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

export default function App() {
  return (
    <>
      <Greeting name="Sara" />
      <Greeting name="Cahal" />
      <Greeting name="Edite" />
    </>
  );
}


Миграция компонента со состоянием из класса в функцию

Предположим, вы конвертируете этот Counter компонент-класс в функцию:

import { Component } from 'react';

export default class Counter extends Component {
  state = {
    name: 'Taylor',
    age: 42,
  };

  handleNameChange = (e) => {
    this.setState({
      name: e.target.value
    });
  }

  handleAgeChange = (e) => {
    this.setState({
      age: this.state.age + 1 
    });
  };

  render() {
    return (
      <>
        <input
          value={this.state.name}
          onChange={this.handleNameChange}
        />
        <button onClick={this.handleAgeChange}>
          Increment age
        </button>
        <p>Hello, {this.state.name}. You are {this.state.age}.</p>
      </>
    );
  }
}

Начните с объявления функции с необходимыми переменными состояния:

import { useState } from 'react';

function Counter() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);
  // ...

Далее, преобразуйте обработчики событий:

function Counter() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);

  function handleNameChange(e) {
    setName(e.target.value);
  }

  function handleAgeChange() {
    setAge(age + 1);
  }
  // ...

Наконец, замените все ссылки, начинающиеся с this, переменными и функциями, которые вы определили в своем компоненте. Например, замените this.state.age на age, а this.handleNameChange на handleNameChange.

Вот полностью преобразованный компонент:

import { useState } from 'react';

export default function Counter() {
  const [name, setName] = useState('Taylor');
  const [age, setAge] = useState(42);

  function handleNameChange(e) {
    setName(e.target.value);
  }

  function handleAgeChange() {
    setAge(age + 1);
  }

  return (
    <>
      <input
        value={name}
        onChange={handleNameChange}
      />
      <button onClick={handleAgeChange}>
        Increment age
      </button>
      <p>Hello, {name}. You are {age}.</p>
    </>
  )
}


Миграция компонента с методами жизненного цикла из класса в функцию

Предположим, вы конвертируете этот ChatRoom компонент-класс с методами жизненного цикла в функцию:

import { Component } from 'react';
import { createConnection } from './chat.js';

export default class ChatRoom extends Component {
  state = {
    serverUrl: 'https://localhost:1234'
  };

  componentDidMount() {
    this.setupConnection();
  }

  componentDidUpdate(prevProps, prevState) {
    if (
      this.props.roomId !== prevProps.roomId ||
      this.state.serverUrl !== prevState.serverUrl
    ) {
      this.destroyConnection();
      this.setupConnection();
    }
  }

  componentWillUnmount() {
    this.destroyConnection();
  }

  setupConnection() {
    this.connection = createConnection(
      this.state.serverUrl,
      this.props.roomId
    );
    this.connection.connect();    
  }

  destroyConnection() {
    this.connection.disconnect();
    this.connection = null;
  }

  render() {
    return (
      <>
        <label>
          Server URL:{' '}
          <input
            value={this.state.serverUrl}
            onChange={e => {
              this.setState({
                serverUrl: e.target.value
              });
            }}
          />
        </label>
        <h1>Welcome to the {this.props.roomId} room!</h1>
      </>
    );
  }
}

Сначала убедитесь, что ваш componentWillUnmount делает обратное componentDidMount. В приведенном выше примере это верно: он отсоединяет соединение, которое componentDidMount устанавливает. Если такой логики нет, добавьте ее сначала.

Далее, убедитесь, что ваш componentDidUpdate метод обрабатывает изменения любых свойств и состояния, которые вы используете в componentDidMount. В приведенном выше примере componentDidMount вызывает setupConnection, который читает this.state.serverUrl и this.props.roomId. Вот почему componentDidUpdate проверяет, изменились ли this.state.serverUrl и this.props.roomId, и сбрасывает соединение, если они изменились. Если ваша логика componentDidUpdate отсутствует или не обрабатывает изменения всех соответствующих свойств и состояния, исправьте это сначала.

В приведенном выше примере логика внутри методов жизненного цикла соединяет компонент с системой за пределами React (сервером чата). Для подключения компонента к внешней системе, опишите эту логику как один эффект:

import { useState, useEffect } from 'react';

function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [serverUrl, roomId]);

  // ...
}

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

import { useState, useEffect } from 'react';
import { createConnection } from './chat.js';

export default function ChatRoom({ roomId }) {
  const [serverUrl, setServerUrl] = useState('https://localhost:1234');

  useEffect(() => {
    const connection = createConnection(serverUrl, roomId);
    connection.connect();
    return () => {
      connection.disconnect();
    };
  }, [roomId, serverUrl]);

  return (
    <>
      <label>
        Server URL:{' '}
        <input
          value={serverUrl}
          onChange={e => setServerUrl(e.target.value)}
        />
      </label>
      <h1>Welcome to the {roomId} room!</h1>
    </>
  );
}

Примечание

Если ваш компонент не синхронизируется с какими-либо внешними системами, вам может не потребоваться эффект.


Миграция компонента с контекстом из класса в функцию

В этом примере компоненты-классы Panel и Button считывают контекст из this.context:

import { createContext, Component } from 'react';

const ThemeContext = createContext(null);

class Panel extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'panel-' + theme;
    return (
      <section className={className}>
        <h1>{this.props.title}</h1>
        {this.props.children}
      </section>
    );    
  }
}

class Button extends Component {
  static contextType = ThemeContext;

  render() {
    const theme = this.context;
    const className = 'button-' + theme;
    return (
      <button className={className}>
        {this.props.children}
      </button>
    );
  }
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

При преобразовании их в компоненты-функции замените this.context вызовами useContext:

import { createContext, useContext } from 'react';

const ThemeContext = createContext(null);

function Panel({ title, children }) {
  const theme = useContext(ThemeContext);
  const className = 'panel-' + theme;
  return (
    <section className={className}>
      <h1>{title}</h1>
      {children}
    </section>
  )
}

function Button({ children }) {
  const theme = useContext(ThemeContext);
  const className = 'button-' + theme;
  return (
    <button className={className}>
      {children}
    </button>
  );
}

function Form() {
  return (
    <Panel title="Welcome">
      <Button>Sign up</Button>
      <Button>Log in</Button>
    </Panel>
  );
}

export default function MyApp() {
  return (
    <ThemeContext.Provider value="dark">
      <Form />
    </ThemeContext.Provider>
  )
}

© 2013–present Facebook Inc.
Licensed under the Creative Commons Attribution 4.0 International Public License.
https://18.react.dev/reference/react/Component

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API