web-dev-qa-db-fra.com

Comment utiliser la méthode de cycle de vie getDerivedStateFromProps par opposition à composantWillReceiveProps

Il semble que componentWillReceiveProps soit complètement éliminé dans les versions à venir, au profit d'une nouvelle méthode de cycle de vie getDerivedStateFromProps: static getDerivedStateFromProps () .

Lors de l'inspection, il semble que vous ne puissiez pas établir de comparaison directe entre this.props et nextProps, comme vous pouvez le faire dans componentWillReceiveProps. Y a-t-il un moyen de contourner cela?

En outre, il retourne maintenant un objet. Ai-je raison de supposer que la valeur de retour est essentiellement this.setState?

Voici un exemple que j'ai trouvé en ligne: Etat dérivé de props/state .

Avant

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

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

Après

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

À propos de la suppression de componentWillReceiveProps: vous devriez être en mesure de gérer ses utilisations avec une combinaison de getDerivedStateFromProps et componentDidUpdate, voir l'article de blog React) par exemple les migrations. Et oui, l'objet renvoyé par getDerivedStateFromProps met à jour l'état de la même manière qu'un objet transmis à setState.

Si vous avez vraiment besoin de l'ancienne valeur d'un accessoire, vous pouvez toujours la mettre en cache dans votre état avec quelque chose comme ceci:

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

Tout ce qui n'affecte pas l'état peut être mis dans componentDidUpdate, et il y a même un getSnapshotBeforeUpdate pour les éléments de très bas niveau.

MISE À JOUR: Pour avoir une idée des nouvelles (et anciennes) méthodes de cycle de vie, le package react-lifecycle-visualizer peut être utile.

73
Oblosys

Comme nous récemment posté sur le blog React _ , dans la grande majorité des cas vous n'avez pas du tout besoin de getDerivedStateFromProps.

Si vous souhaitez simplement calculer des données dérivées, vous pouvez soit:

  1. Faites-le directement à l'intérieur render
  2. Ou, si le recalcul est coûteux, utilisez un assistant de mémoization tel que memoize-one.

Voici l'exemple "après" le plus simple:

import memoize from "memoize-one";

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

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

Découvrez cette section de l'article pour en savoir plus.

34
Dan Abramov

Comme mentionné par Dan Abramov

Faites-le bien à l'intérieur

En fait, nous utilisons cette approche avec memoise one pour n’importe quel type d’accessoires proxy permettant d’établir des calculs.

Notre code ressemble à ça

// ./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>
    );
  }
}

L'avantage de cette méthode est que vous n'avez pas besoin de coder des tonnes de comparaisons entre les éléments getDerivedStateFromProps ou componentWillReceiveProps et vous pouvez ignorer l'initialisation du copier-coller dans un constructeur.

NOTE:

Cette approche est utilisée uniquement pour représenter les accessoires par proxy, au cas où vous auriez une logique d'état interne, celle-ci doit encore être traitée dans les cycles de vie des composants.

3
mpospelov