Verwendung der Lebenszyklusmethode getDerivedStateFromProps im Gegensatz zu componentWillReceiveProps

142

Es sieht so aus, componentWillReceivePropsals würde es in den kommenden Releases zugunsten einer neuen Lebenszyklusmethode vollständig auslaufen getDerivedStateFromProps: statisch getDerivedStateFromProps () .

Nach der Inspektion sieht es so aus, als ob Sie jetzt keinen direkten Vergleich zwischen this.propsund durchführen können nextProps, wie Sie es können componentWillReceiveProps. Gibt es einen Weg daran vorbei?

Außerdem wird jetzt ein Objekt zurückgegeben. Kann ich zu Recht davon ausgehen, dass der Rückgabewert im Wesentlichen ist this.setState?

Unten ist ein Beispiel, das ich online gefunden habe: Status abgeleitet von Requisiten / Status .

Vor

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

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

Nach dem

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

Antworten:

96

Informationen zum Entfernen von componentWillReceiveProps: Sie sollten in der Lage sein, die Verwendung mit einer Kombination aus getDerivedStateFromPropsund zu handhaben. Weitere Informationen findencomponentDidUpdate Sie im React-Blogbeitrag, z. B. zu Migrationen. Und ja, das von zurückgegebene Objekt getDerivedStateFromPropsaktualisiert den Status ähnlich wie ein übergebenes Objekt setState.

Wenn Sie den alten Wert einer Requisite wirklich benötigen, können Sie ihn jederzeit in Ihrem Status mit folgendem Cache zwischenspeichern:

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

Alles, was den Zustand nicht beeinflusst, kann eingegeben werden componentDidUpdate, und es gibt sogar Dinge getSnapshotBeforeUpdatefür sehr niedrige Level.

UPDATE: Um ein Gefühl für die neuen (und alten) Lebenszyklusmethoden zu bekommen, kann das Paket React-Lifecycle-Visualizer hilfreich sein.

Oblosys
quelle
1
Ugh, ich habe die Frage durcheinander gebracht. Ich meinte eigentlichcomponentWillReceiveProps
Andrew
2
Ich hatte darüber nachgedacht, meinen Status zum Speichern früherer Requisiten zu verwenden, wollte aber unbedingt den zusätzlichen Code und die Logik vermeiden, die für die Implementierung erforderlich sind. Ich werde einige der anderen Dinge untersuchen, die Sie ansprechen. Vielen Dank!
Andrew
4
Das Speichern einer vorherigen Requisite in einem Status ist nur eine Problemumgehung für diese schwer verständliche Änderung der React-API. Für viele Entwickler sieht dies wie ein Antimuster und eine Regressionsänderung aus. Ich kritisiere dich nicht, Oblosys, sondern das React-Team.
AxeEffect
2
@AxeEffect Dies liegt daran, dass getDerivedStateFromPropses nie wirklich zum Auswendiglernen gedacht war . Bitte lesen Sie meine Antwort unten, in der ich stattdessen den empfohlenen Ansatz beschrieben habe .
Dan Abramov
ist das ein Tippfehler? Haben Sie vermissen ...? Das heißt, sollten wir das gesamte Zustandsobjekt oder nur den Teil zurückgeben, der uns wichtig ist.
Programmierer
51

Wie wir vor kurzem auf dem Blog Reagieren geschrieben , in der überwiegenden Mehrzahl der Fälle die Sie nicht brauchen getDerivedStateFromPropsüberhaupt .

Wenn Sie nur einige abgeleitete Daten berechnen möchten, gehen Sie wie folgt vor:

  1. Mach es gleich drinnen render
  2. Oder, wenn eine Neuberechnung teuer ist, verwenden Sie einen Memoization Helper wie memoize-one.

Hier ist das einfachste "Nach" -Beispiel:

import memoize from "memoize-one";

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

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

In diesem Abschnitt des Blogposts erfahren Sie mehr.

Dan Abramov
quelle
45
Wenn es in den allermeisten Fällen nicht benötigt wird, bin ich überrascht, dass dies eine dringend benötigte Änderung war, die Tausende von Arbeitsprojekten zum Erliegen bringen wird. Es sieht so aus, als hätte das React-Team mit dem Engineering begonnen.
Ska
39
Wechseln Sie von componentWillReceiveProps zu getDerivedStateFromProps. Es ist nicht kaputt, sondern zwingt dazu, den gesamten vorhandenen Code umzugestalten, was sehr zeitaufwändig ist. Und scheint sehr wenig zu nützen, da Sie sagen, dass Sie es in den allermeisten Fällen überhaupt nicht verwenden sollten. Warum sollten Sie sich die Mühe machen, die API für etwas zu ändern, das überhaupt nicht verwendet werden sollte?
Ska
4
Ich würde eine Antwort auf diesen Kommentar von Dan Abramov lieben.
Louis345
6
@ DanAbramov eine Antwort darauf, warum diese Änderung kam?
Petros Kyriakou
3
Tatsächlich wird dies in unseren Projekten häufig verwendet. Ein Beispiel für die Anzeige von Snackbars auf Bildschirmen, wenn neue Daten herunterkommen. componentWillReceivePropswar einfach und es hat funktioniert. Warum es für diesen statischen Müll entfernen ...
Oliver Dixon
6

Wie von Dan Abramov erwähnt

Mach es direkt im Rendering

Wir verwenden diesen Ansatz tatsächlich mit Memoise One für jede Art von Proxy-Requisiten für Zustandsberechnungen.

Unser Code sieht so aus

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

Die Vorteile davon sind, dass Sie nicht Tonnen von Vergleichs-Boilerplates im Inneren codieren müssen getDerivedStateFromPropsoder die componentWillReceivePropsInitialisierung durch Kopieren und Einfügen in einem Konstruktor überspringen können.

HINWEIS:

Dieser Ansatz wird nur verwendet, um die Requisiten auf den Status zu übertragen. Wenn Sie über eine innere Statuslogik verfügen, muss diese weiterhin in den Komponentenlebenszyklen behandelt werden.

mpospelov
quelle