Як використовувати метод життєвого циклу 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.