Reagieren Sie den Initialisierungsstatus der Komponente von den Requisiten

204

Gibt es in React echte Unterschiede zwischen diesen beiden Implementierungen? Einige Freunde sagen mir, dass die FirstComponent das Muster ist, aber ich verstehe nicht warum. Die SecondComponent scheint einfacher zu sein, da das Rendern nur einmal aufgerufen wird.

Zuerst:

import React, { PropTypes } from 'react'

class FirstComponent extends React.Component {

  state = {
    description: ''
  }

  componentDidMount() {
    const { description} = this.props;
    this.setState({ description });
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} /> 
    );
  }
}

export default FirstComponent;

Zweite:

import React, { PropTypes } from 'react'

class SecondComponent extends React.Component {

  state = {
    description: ''
  }

  constructor (props) => {
    const { description } = props;
    this.state = {description};
  }

  render () {
    const {state: { description }} = this;    
    return (
      <input type="text" value={description} />   
    );
  }
}

export default SecondComponent;

Update: Ich habe setState () in this.state = {} geändert (danke joews). Ich sehe jedoch immer noch keinen Unterschied. Ist einer besser als der andere?

Levy Moreira
quelle
10
Warum lagern Sie Ihre Requisiten im Staat? Sie sollten Ihre Requisiten stattdessen direkt verwenden, anstatt einen Wert zwischenzuspeichern. Lesen Sie, warum das Festlegen von Requisiten als Status in React.js Blasphemie ist und Requisiten in getInitialState ein Anti-Pattern sind .
Aurora0001
12
Ein Beispiel - eine umschaltbare Komponente (z. B. ein Popover oder eine Schublade). Der Elternteil weiß, ob die Komponente offen oder geschlossen gestartet werden soll. Die Komponente selbst weiß möglicherweise, ob sie zu einem bestimmten Zeitpunkt geöffnet ist oder nicht. In diesem Fall halte ich es für this.state = { isVisible: props.isVisible }sinnvoll. Hängt davon ab, wie die App den UI-Status verteilt.
Joews
2
Sie sollten dieses Medium lesen.com/@justintulk/…
FDisk
5
Im Jahr 2017 demonstriert Facebook die Verwendung von Requisiten, um den Anfangszustand in ihrer Dokumentation festzulegen
Rohmer
1
@ Aurora0001 Was ist mit einer Situation, in der Sie ein Formular bearbeiten müssen, z. B. ein Bearbeitungsformular, das Netzwerkanforderungen selbst erstellt, die Eingaben jedoch mit Werten initialisiert, die als Requisiten für diese Komponente dienen würden? Um das Formular dynamisch zu halten, müssen diese Werte beibehalten werden.
Eric McWinNEr

Antworten:

196

Es sollte beachtet werden, dass es ein Anti-Pattern ist, Eigenschaften zu kopieren, die sich nie in den Status ändern (in diesem Fall einfach direkt auf .props zugreifen). Wenn Sie eine Statusvariable haben, die sich irgendwann ändert, aber mit einem Wert von .props beginnt, benötigen Sie nicht einmal einen Konstruktoraufruf. Diese lokalen Variablen werden nach einem Aufruf des Konstruktors des übergeordneten Elements initialisiert:

class FirstComponent extends React.Component {
  state = {
    x: this.props.initialX,
    // You can even call functions and class methods:
    y: this.someMethod(this.props.initialY),
  };
}

Dies ist eine Kurzform, die der Antwort von @joews unten entspricht. Es scheint nur auf neueren Versionen von es6-Transpilern zu funktionieren. Ich hatte Probleme damit bei einigen Webpack-Setups. Wenn dies bei Ihnen nicht funktioniert, können Sie versuchen, das Babel-Plugin hinzuzufügen babel-plugin-transform-class-properties, oder Sie können die Nicht-Kurzschrift-Version von @joews unten verwenden.

Zane Hooper
quelle
1
Können Sie mehr erklären, wie sich Ihre Antwort von der Antwort von @joews unterscheidet?
Jalal
3
Hinzugefügt "Sie können den Konstruktoraufruf überspringen, wenn Sie nur Variablen festlegen."
Zane Hooper
3
Wenn es nicht funktioniert, müssen Sie wahrscheinlich dieses Babel-Plugin "Babel-Plugin-Transform-Class-Eigenschaften" installieren.
Faheem
2
Es ist kein Anti-Muster, den Status von Requisiten zu initialisieren, wenn verstanden wird, dass der Status nach der Initialisierung nicht auf die Requisiten angewiesen ist. Wenn Sie versuchen, die beiden synchron zu halten , ist dies ein Anti-Pattern.
Yatrix
1
@ ak85 es ist die gleiche Syntax, aber Sie würden stattdessen this.state verwenden. Diese Syntax ist nur eine Kurzsyntax zum Festlegen des Status während des Klassenkonstruktionsprozesses (und kann auch für andere Variablen als den Status verwendet werden)
Zane Hooper
137

Sie müssen keine setStateKomponenten aufrufen constructor- es ist idiomatisch, this.statedirekt festzulegen :

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      x: props.initialX
    };
  }
  // ...
}

Siehe React docs - Hinzufügen eines lokalen Status zu einer Klasse .

Die erste Methode, die Sie beschreiben, hat keinen Vorteil. Unmittelbar vor dem ersten Mounten der Komponente wird ein zweites Update durchgeführt.

Joews
quelle
4
Gute Antwort. Es kann erwähnenswert sein, dass dies nur zum Einstellen des Ausgangszustands dient. Sie müssen es weiterhin verwenden, setStatewenn Sie es an einem anderen Punkt mutieren, da die Änderungen sonst möglicherweise nicht gerendert werden.
Aurora0001
Nochmals vielen Dank Jowes, zweitens die Dokumentation facebook.github.io/react/docs/…
Levy Moreira
(Entschuldigung, ich drücke die Eingabetaste.) Wir sollten den getInitialState verwenden, um die Requisiten in komplexeren Aufgaben auf den Status zu setzen. Wenn es einfach ist, können wir einfach die this.props für das Rendern verwenden, richtig?
Levy Moreira
1
Randbemerkung: Verwendung super(props)im Konstruktor. Diskussion über SO
Cutemachine
2
Der Vorschlag von joews funktioniert in den meisten Fällen, aber seien Sie vorsichtig, wenn Sie Requisiten direkt an this.state senden. Das Kopieren von Requisiten in diesen Zustand ist eigentlich keine einzige Quelle der Wahrheit ( medium.com/react-ecosystem/… ). Außerdem schlug Dan Abramov einmal vor, die Werte der Requisiten nicht im Zustand zu speichern. ( twitter.com/dan_abramov/status/749710501916139520/photo/1 ).
Hiroki
33

Update für React 16.3 Alpha eingeführt static getDerivedStateFromProps(nextProps, prevState)( docs ) als Ersatz für componentWillReceiveProps.

getDerivedStateFromProps wird aufgerufen, nachdem eine Komponente instanziiert wurde und wenn sie neue Requisiten erhält. Es sollte ein Objekt zurückgeben, um den Status zu aktualisieren, oder null, um anzuzeigen, dass für die neuen Requisiten keine Statusaktualisierungen erforderlich sind.

Beachten Sie, dass diese Methode aufgerufen wird, wenn eine übergeordnete Komponente dazu führt, dass Ihre Komponente erneut gerendert wird, auch wenn sich die Requisiten nicht geändert haben. Möglicherweise möchten Sie neue und vorherige Werte vergleichen, wenn Sie nur Änderungen verarbeiten möchten.

https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

Es ist statisch, daher ist es nicht direkten Zugriff hat this(allerdings hat es Zugang zu haben prevState, die Dinge normalerweise angebracht speichern könnte thiszB refs)

bearbeitet, um die Korrektur von @ nerfologist in den Kommentaren wiederzugeben

Ashley Coolman
quelle
3
Nur um zu klären, wird es genannt getDerivedStateFromProps(die Großbuchstaben in Props markiert) und die params sind nextProps, prevState(nicht nextState): reactjs.org/docs/...
nerfologist
1
Beeindruckend! Wir können dies verwenden, um den Status zu aktualisieren, wenn aktualisierte Requisiten empfangen werden!
Aromal Sasidharan
2
Müssen wir den Anfangszustand noch im Konstruktor erstellen, wenn man bedenkt, dass der getDerivedStateFromPropsimmer vor dem anfänglichen Rendern aufgerufen wird?
Bvdb
19

Sie können die folgende Kurzform verwenden, wenn Sie alle Requisiten hinzufügen möchten, um dieselben Namen anzugeben und beizubehalten.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
dacharjaya
quelle
1
Es ist ein Anti-Pattern, um Eigenschaften zu kopieren, die sich nie in den Status ändern. Es ist besser, explizit zu beschreiben, welche Felder Ihre Komponente verwendet.
Michael Freidgeim
5

Stellen Sie die Statusdaten im Konstruktor wie folgt ein

constructor(props) {
    super(props);
    this.state = {
      productdatail: this.props.productdetailProps
    };
  }

Es wird nicht funktionieren, wenn Sie die Methode side componentDidMount () über Requisiten festlegen.

Krishna Kumar Jangid
quelle
3

Wenn Sie den Status direkt von Requisiten aus starten, wird in React 16.5 (5. September 2018) eine Warnung angezeigt.

Sujith S.
quelle
Irgendeine Idee, warum es warnen wird?
Nitin Jadhav
2
Es sieht so aus, als ob es nur ist, wenn Sie es verwenden state = props. Weitere Infos hier: github.com/facebook/react/pull/11658#issuecomment-419677176
jetzt
1

Sie können componentWillReceiveProps verwenden.

constructor(props) {
    super(props);
    this.state = {
      productdatail: ''
    };
  }

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }
Ankit Kumar Rajpoot
quelle
1
componentWillReceiveProps ist veraltet und kann nicht für zukünftige Versionen verwendet werden
Vivek Ghanchi
1

Du musst vorsichtig sein , wenn Sie initialisieren statevon propsim Konstruktor. Selbst wenn propsder Status auf einen neuen geändert würde, würde er nicht geändert, da das Mount nie wieder vorkommt. Also getDerivedStateFromPropsexistiert dafür.

class FirstComponent extends React.Component {
    state = {
        description: ""
    };

    static getDerivedStateFromProps(nextProps, prevState) {
        if (prevState.description !== nextProps.description) {
          return { description: nextProps.description };
        }

        return null;
    }

    render() {
        const {state: {description}} = this;    

        return (
            <input type="text" value={description} /> 
        );
    }
}
Yonggoo Noh
quelle