Как использовать метод lifecycle getDerivedStateFromProps, а не componentWillReceiveProps

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

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

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

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

Перед

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

  componentWillReceiveProps(nextProps) {
    if (this.props.someValue !== nextProps.someValue) {
      this.setState({
        derivedData: computeDerivedState(nextProps)
      });
    }
  }
}
После того, как

After

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;
  }
}

Ответ 1

Об удалении 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 для вещей очень низкого уровня.

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

Ответ 2

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

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

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

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

import memoize from "memoize-one";

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

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

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

Ответ 3

Как упоминал Дэн Абрамов

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

Мы на самом деле используем этот подход с 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 и вы можете пропустить инициализацию копий-пасты внутри конструктора.

ЗАМЕТКА:

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