Як використовувати метод життєвого циклу getDerivedStateFromProps на відміну від компонентаWillReceiveProps


142

Схоже componentWillReceiveProps, в наступних випусках буде повністю припинено використання на користь нового методу життєвого циклу getDerivedStateFromProps: статичного 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)
      });
    }
  }
}

Після

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

Відповіді:


96

Про видалення 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речі для дуже низького рівня.

ОНОВЛЕННЯ: Щоб відчути нові (і старі) методи життєвого циклу, може бути корисним пакет візуалізаторів реагування на життєвий цикл .


1
Фу, я переплутав це питання. Я насправді мав на увазіcomponentWillReceiveProps
Андрій

2
Я думав використовувати свій стан для утримання попередніх реквізитів, але дуже хотів уникнути зайвого коду та логіки, необхідної для його реалізації. Я роздивляюся деякі інші речі, які ви виховуєте. Дуже дякую!
Андрій

4
Зберігання попередньої опори у стані - це лише вирішення проблеми для важкої для розуміння API React. Для очей багатьох розробників це виглядає як антипаттерн і регресія. Не критикуючи вас Oblosys, а команду React.
AxeEffect

2
@AxeEffect Це тому, що getDerivedStateFromPropsніколи насправді не призначався для запам'ятовування . Будь ласка, дивіться мою відповідь нижче, де я описав рекомендований підхід .
Дан Абрамов

це помилка друку? Ви сумували ...? Тобто ми повинні повернути весь державний об'єкт або лише ту частину, яка нас хвилює.
theprogrammer

51

Як ми нещодавно опублікував на 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);
    // ...
  }
}

Перегляньте цей розділ публікації щоденника, щоб дізнатися більше.


45
Якщо вона не потрібна у переважній більшості випадків, то я здивований, що це була така вкрай необхідна зміна, яка порушить тисячі робочих проектів. Схоже, команда React почала займатися розробкою.
Ска

39
Перехід від компонента компонента WillReceiveProps до getDerivedStateFromProps. Це не зламати, а змусити рефакторировать весь існуючий код, що забирає багато часу. І, здається, це дуже мало користі, оскільки ви говорите, що ви не повинні використовувати його взагалі у переважній більшості випадків. Навіщо переживати проблеми з зміною API для чогось, що навіть не слід використовувати в першу чергу.
Ска

4
Я хотів би відповісти на цей коментар від Дана Абрамова.
Louis345

6
@DanAbramov будь-яка відповідь, чому ця зміна сталася?
Петрос

3
Насправді в наших проектах це використовується багато. Для показу таких речей, як закусочні на екранах, коли з’являються нові дані, 1 приклад. componentWillReceivePropsбуло просто, і це спрацювало. Навіщо прибирати його для цього статичного сміття ...
Олівер Діксон,

6

Як згадував Дан Абрамов

Зробіть це всередині візуалізації

Ми фактично використовуємо цей підхід із пам'ятною запискою для будь-якого виду супутніх реквізитів до державних розрахунків.

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

// ./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 і ви можете пропустити копіпаст ініціалізації в конструкторі.

ПРИМІТКА:

Цей підхід використовується лише для наближення реквізиту до стану, якщо у вас є певна логіка внутрішнього стану, з ним все-таки потрібно обробляти в життєвих циклах компонентів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.