Как использовать метод жизненного цикла getDerivedStateFromProps вместо componentWillReceiveProps

150

Похоже, что componentWillReceivePropsв следующих выпусках он будет полностью прекращен в пользу нового метода жизненного цикла getDerivedStateFromProps: static getDerivedStateFromProps () .

При осмотре похоже, что теперь вы не можете провести прямое сравнение между this.propsи nextProps, как вы можете в componentWillReceiveProps. Есть ли способ обойти это?

Кроме того, теперь он возвращает объект. Правильно ли я предполагаю, что возвращаемое значение по существу this.setState?

Ниже приведен пример, который я нашел в Интернете: Состояние, полученное из props / state .

Перед

class ExampleComponent extends React.Component {
  state = {
    derivedData: computeDerivedState(this.props)
  };

  componentWillReceiveProps(nextProps) {
    if (this.props.someValue !== nextProps.someValue) {
      this.setState({
        derivedData: computeDerivedState(nextProps)
      });
    }
  }
}

После

class ExampleComponent extends React.Component {
  // Initialize state in constructor,
  // Or with a property initializer.
  state = {};

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.someMirroredValue !== nextProps.someValue) {
      return {
        derivedData: computeDerivedState(nextProps),
        someMirroredValue: nextProps.someValue
      };
    }

    // Return null to indicate no change to state.
    return null;
  }
}
Андрей
источник

Ответы:

103

Об удалении componentWillReceiveProps: вы должны иметь возможность обрабатывать его использование с помощью комбинации getDerivedStateFromPropsи componentDidUpdate, см. Сообщение в блоге React, например, миграции. И да, объект, возвращаемый функцией, getDerivedStateFromPropsобновляет состояние аналогично переданному объекту setState.

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

state = {
  cachedSomeProp: null
  // ... rest of initial state
};

static getDerivedStateFromProps(nextProps, prevState) {
  // do things with nextProps.someProp and prevState.cachedSomeProp
  return {
    cachedSomeProp: nextProps.someProp,
    // ... other derived state properties
  };
}

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

ОБНОВЛЕНИЕ. Чтобы получить представление о новых (и старых) методах жизненного цикла , может оказаться полезным пакет react-lifecycle-visualizer .

Oblosys
источник
1
Тьфу, я перепутала вопрос. На самом деле я имел в видуcomponentWillReceiveProps
Эндрю
2
Я думал использовать свое состояние для хранения предыдущих свойств, но мне действительно хотелось избежать лишнего кода и логики, необходимых для его реализации. Я рассмотрю некоторые другие вопросы, о которых вы говорите. Большое спасибо!
Эндрю
4
Необходимость сохранить предыдущую опору в состоянии - это всего лишь шаблонный обходной путь для этого трудного для понимания изменения API React. Для многих разработчиков это выглядит как антипаттерн и регресс. Критикует не вас, Oblosys, а команду React.
AxeEffect
2
@AxeEffect Это потому, что getDerivedStateFromPropsникогда не предназначалось для мемоизации . См. Мой ответ ниже, где я описал рекомендуемый подход .
Дан Абрамов
это опечатка? Вы пропустили ...? То есть должны мы вернуть весь объект состояния или только ту часть, которая нам нужна.
theprogrammer
55

Как мы недавно опубликовал на React блог , в подавляющем большинстве случаев вам не нужно getDerivedStateFromPropsвообще .

Если вы просто хотите вычислить производные данные, либо:

  1. Сделай это прямо внутри render
  2. Или, если пересчет требует больших затрат, используйте помощник по запоминанию, например memoize-one.

Вот простейший пример «после»:

import memoize from "memoize-one";

class ExampleComponent extends React.Component {
  getDerivedData = memoize(computeDerivedState);

  render() {
    const derivedData = this.getDerivedData(this.props.someValue);
    // ...
  }
}

Прочтите этот раздел сообщения в блоге, чтобы узнать больше.

Дан Абрамов
источник
47
Если в подавляющем большинстве случаев в этом нет необходимости , то я удивлен, что это было настолько необходимое изменение, которое сломает тысячи рабочих проектов. Похоже, команда React начала с инженерии.
Ska
40
Измените значение componentWillReceiveProps на getDerivedStateFromProps. Это не ломает, а заставляет рефакторинг всего существующего кода, что отнимает очень много времени. И, похоже, очень мало пользы, поскольку вы говорите, что не должны использовать его вообще в подавляющем большинстве случаев. Зачем тратить время на смену API на то, что вообще не следует использовать.
Ska
4
Я хотел бы получить ответ на этот комментарий от Дэна Абрамова.
Louis345
6
@DanAbramov есть ли ответ на вопрос, почему это изменение произошло?
Петрос Кириаку 03
3
На самом деле в наших проектах это используется очень часто. Для отображения таких вещей, как Snackbars на экранах, когда появляются новые данные, 1 пример. componentWillReceivePropsбыло просто, и это сработало. Зачем убирать его из-за этого статического мусора ...
Оливер Диксон
6

Как сказал Дан Абрамов

Сделайте это прямо внутри рендера

На самом деле мы используем этот подход с memoise one для любого типа прокси для констатации вычислений.

Наш код выглядит так

// ./decorators/memoized.js  
import memoizeOne from 'memoize-one';

export function memoized(target, key, descriptor) {
  descriptor.value = memoizeOne(descriptor.value);
  return descriptor;
}

// ./components/exampleComponent.js
import React from 'react';
import { memoized } from 'src/decorators';

class ExampleComponent extends React.Component {
  buildValuesFromProps() {
    const {
      watchedProp1,
      watchedProp2,
      watchedProp3,
      watchedProp4,
      watchedProp5,
    } = this.props
    return {
      value1: buildValue1(watchedProp1, watchedProp2),
      value2: buildValue2(watchedProp1, watchedProp3, watchedProp5),
      value3: buildValue3(watchedProp3, watchedProp4, watchedProp5),
    }
  }

  @memoized
  buildValue1(watchedProp1, watchedProp2) {
    return ...;
  }

  @memoized
  buildValue2(watchedProp1, watchedProp3, watchedProp5) {
    return ...;
  }

  @memoized
  buildValue3(watchedProp3, watchedProp4, watchedProp5) {
    return ...;
  }

  render() {
    const {
      value1,
      value2,
      value3
    } = this.buildValuesFromProps();

    return (
      <div>
        <Component1 value={value1}>
        <Component2 value={value2}>
        <Component3 value={value3}>
      </div>
    );
  }
}

Преимущества в том, что вам не нужно кодировать тонны шаблонов сравнения внутри getDerivedStateFromPropsили componentWillReceivePropsвы можете пропустить инициализацию копирования и вставки внутри конструктора.

НОТА:

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

мпоспелов
источник
0

getDerivedStateFromProps используется всякий раз, когда вы хотите обновить состояние перед рендерингом и обновить состояние реквизита

GetDerivedStateFromPropd обновляет значение статистики с помощью значения props

прочтите https://www.w3schools.com/REACT/react_lifecycle.asp#:~:text=Lifecycle%20of%20Components,Mounting%2C%20Updating%2C%20and%20Unmounting .

СоуМитя чаухан
источник