какая разница между getDerivedStateFromError и componentDidCatch

Что я понял отсюда:

componentDidCatch:

  • всегда вызывается в браузере
  • вызывается во время "фазы фиксации", когда DOM уже обновлен
  • следует использовать для чего-то вроде сообщения об ошибках

getDerivedStateFromError:

  • также вызывается во время рендеринга на стороне сервера
  • вызывается перед "фазой фиксации", когда DOM еще не обновлен
  • должен использоваться для рендеринга резервного интерфейса

Тем не менее, я немного запутался в некоторых вещах:

  1. они оба ловят один и тот же тип ошибок? или каждый жизненный цикл будет ловить разные ошибки?
  2. я должен всегда использовать оба (в том же самом компоненте "ловли ошибок" возможно)?
  3. "использование componentDidCatch для восстановления после ошибок не является оптимальным, потому что оно заставляет резервный интерфейс всегда отображаться синхронно", что с этим не так?

Ответ 1

Утверждения в вопросе в основном правильные. В настоящее время границы ошибок не поддерживаются в SSR, getDerivedStateFromError и componentDidCatch не влияют на сторону сервера.

они оба ловят один и тот же тип ошибок? или каждый жизненный цикл будет ловить разные ошибки?

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

  static getDerivedStateFromError() {
    return { hasError: true };
  }

а также

  componentDidCatch() {
    this.setState({ hasError: true });
  }

Сделайте то же самое, у componentDidCatch нет шансов на поддержку на стороне сервера, пока в ReactDOMServer не будет добавлена поддержка асинхронного рендеринга.

я должен всегда использовать оба (в том же самом компоненте "ловли ошибок" возможно)?

Вы можете использовать оба. Пример из документации показывает, что:

class ErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, info) {
    logComponentStackToMyService(info.componentStack);
  }

  render() {
    if (this.state.hasError) {
      return <h1>Something went wrong.</h1>;
    }

    return this.props.children; 
  }
}

В этом случае обязанности распределяются между ними. getDerivedStateFromError делает только то, для чего он хорош, то есть обновляет состояние в случае возникновения ошибки, в то время как componentDidCatch предоставляет побочные эффекты и при необходимости может получить доступ к this экземпляру компонента.

"использование componentDidCatch для восстановления после ошибок не является оптимальным, потому что оно заставляет резервный интерфейс всегда отображаться синхронно", что с этим не так?

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

Ответ 2

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

Согласно документам React

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


они оба ловят один и тот же тип ошибок? или каждый жизненный цикл будет ловить разные ошибки?

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

В то время как getDerivedStateFromError получает в качестве аргументов только ошибку, componentDidCatch также получает второй параметр, который является info, ie An object with a componentStack key containing information about which component threw the error.

getDerivedStateFromError() вызывается во время фазы "рендеринга", поэтому побочные эффекты не допускаются. Для этих случаев используйте вместо этого componentDidCatch(). Хотя componentDidCatch также может быть использован для setState, но это не рекомендуется в будущих версиях

componentDidCatch должен использоваться для побочных эффектов, таких как ошибки регистрации


Также @Brian Vaughn более подробно рассказал об их использовании по предоставленной вами ссылке.

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

Визуализация фазы восстановления безопаснее. История восстановления после ошибок через componentDidCatch немного неудобна, поскольку она опирается на промежуточную фиксацию "null" для всего, что находится ниже компонента, в котором произошла ошибка. Это может привести к последующим ошибкам внутри любых компонентов выше в дереве, которые реализуют componentDidMount или componentDidUpdate и просто предполагают, что их ссылки будут ненулевыми (потому что они всегда находятся в случае отсутствия ошибок).

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

В случае ошибки getDerivedStateFromError() метод getDerivedStateFromError() границы вашей ошибки (для обновления состояния), затем метод render() (для фактического отображения резервного интерфейса), а затем componentDidCatch (после того, как резервный интерфейс был зафиксирован). в ДОМ).

Если ваша граница ошибки определяет другие методы жизненного цикла (например, componentWillUpdate, componentDidUpdate), они также будут вызваны так же, как и при любом другом рендеринге.


"использование componentDidCatch для восстановления после ошибок не является оптимальным, потому что оно заставляет резервный интерфейс всегда отображаться синхронно", что с этим не так?

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