Composant React initialiser l'état des accessoires

205

Dans React, existe-t-il de réelles différences entre ces deux implémentations? Certains amis me disent que le FirstComponent est le modèle, mais je ne vois pas pourquoi. Le SecondComponent semble plus simple car le rendu n'est appelé qu'une seule fois.

Première:

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;

Seconde:

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;

Mise à jour: j'ai changé setState () en this.state = {} (merci joews), Cependant, je ne vois toujours pas la différence. Est-ce que l'un est meilleur que l'autre?

Levy Moreira
la source
10
Pourquoi stockez-vous vos accessoires en l'état? Vous devez utiliser vos accessoires directement à la place, plutôt que de mettre en cache une valeur. Lisez pourquoi Pourquoi définir les accessoires comme état dans React.js est un blasphème et les accessoires dans getInitialState est un anti-modèle .
Aurora0001
12
Un exemple - un composant à bascule (par exemple un popover ou un tiroir). Le parent sait si le composant doit commencer ouvert ou fermé; le composant lui-même peut savoir s'il est ouvert ou non à un moment donné. Dans ce cas, je pense que this.state = { isVisible: props.isVisible }c'est logique. Dépend de la façon dont l'application distribue l'état de l'interface utilisateur.
joews du
2
Vous devriez lire ce medium.com/@justintulk/…
FDisk
5
En 2017, Facebook montre comment utiliser des accessoires pour définir l'état initial dans leur documentation: reactjs.org/docs/react-component.html#constructor
Rohmer
1
@ Aurora0001 Que se passe-t-il dans une situation où vous devez gérer un formulaire, par exemple un formulaire de modification qui ferait lui-même des demandes réseau, mais vous devez initialiser les entrées avec des valeurs qui viendraient comme accessoires pour ce composant. Afin de garder le formulaire dynamique, ces valeurs doivent être maintenues en état.
Eric McWinNEr

Réponses:

196

Il convient de noter qu'il s'agit d'un anti-modèle pour copier des propriétés qui ne changent jamais en état (accédez simplement à .props directement dans ce cas). Si vous avez une variable d'état qui changera éventuellement mais commence par une valeur de .props, vous n'avez même pas besoin d'un appel de constructeur - ces variables locales sont initialisées après un appel au constructeur du parent:

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

Ceci est un raccourci équivalent à la réponse de @joews ci-dessous. Il semble ne fonctionner que sur les versions plus récentes des transpilateurs es6, j'ai eu des problèmes avec cela sur certaines configurations de webpack. Si cela ne fonctionne pas pour vous, vous pouvez essayer d'ajouter le plugin babel babel-plugin-transform-class-properties, ou vous pouvez utiliser la version non abrégée de @joews ci-dessous.

Zane Hooper
la source
1
pouvez-vous expliquer en quoi votre réponse est différente de la réponse @joews?
Jalal
3
Ajouté "Vous pouvez ignorer l'appel du constructeur si tout ce que vous faites est de définir des variables."
Zane Hooper du
3
Si cela ne fonctionne pas, vous devrez probablement installer ce plugin babel "babel-plugin-transform-class-properties".
Faheem
2
Ce n'est pas un anti-modèle d'initialiser l'état à partir des accessoires s'il est entendu que l'état ne dépend pas des accessoires après l'initialisation. Si vous essayez de garder les deux synchronisés, c'est un anti-modèle.
Yatrix
1
@ ak85 c'est la même syntaxe mais vous utiliseriez this.state à la place. Cette syntaxe est juste une syntaxe abrégée pour définir l'état pendant le processus de construction de la classe (et peut également être utilisée pour des variables autres que l'état)
Zane Hooper
137

Vous n'avez pas besoin d'appeler setStateun composant constructor- il est idiomatique de définir this.statedirectement:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

Voir React docs - Ajout d'un état local à une classe .

Il n'y a aucun avantage à la première méthode que vous décrivez. Il en résultera une deuxième mise à jour immédiatement avant de monter le composant pour la première fois.

joews
la source
4
Bonne réponse. Il peut être utile de noter que cela ne sert qu'à définir l'état initial; vous devez toujours l'utiliser setStatesi vous le mutez à tout autre moment, sinon les modifications risquent de ne pas s'afficher.
Aurora0001
Merci encore jowes, seconde la documentation facebook.github.io/react/docs/…
Levy Moreira
(désolé, j'appuie sur Entrée ..) nous devrions utiliser getInitialState pour définir les accessoires pour indiquer, dans les tâches plus complexes, si c'est simple, nous pouvons simplement utiliser les this.props dans le rendu, correct?
Levy Moreira
1
Sur une note marginale: utilisation super(props)dans le constructeur. Discussion sur SO
cutemachine
2
La suggestion de joews fonctionne dans la plupart des cas, mais soyez prudent lorsque vous envoyez des accessoires directement à this.state. La copie d'accessoires dans this.state est en fait une seule source de vérité ( medium.com/react-ecosystem/… ). En outre, Dan Abramov a suggéré une fois de ne pas stocker les valeurs des accessoires dans l'état. ( twitter.com/dan_abramov/status/749710501916139520/photo/1 ).
Hiroki
33

Mise à jour de React 16.3 alpha introduite static getDerivedStateFromProps(nextProps, prevState)( docs ) en remplacement de componentWillReceiveProps.

getDerivedStateFromProps est invoqué après l'instanciation d'un composant ainsi que lorsqu'il reçoit de nouveaux accessoires. Il doit retourner un objet pour mettre à jour l'état, ou null pour indiquer que les nouveaux accessoires ne nécessitent aucune mise à jour d'état.

Notez que si un composant parent provoque un nouveau rendu de votre composant, cette méthode sera appelée même si les accessoires n'ont pas changé. Vous souhaiterez peut-être comparer les valeurs nouvelles et précédentes si vous souhaitez uniquement gérer les modifications.

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

Il est statique, donc il n'a pas d'accès direct à this(cependant il a accès à prevState, qui pourrait stocker des choses normalement attachées par thisexemple refs)

modifié pour refléter la correction de @ nerfologist dans les commentaires

Ashley Coolman
la source
3
Juste pour clarifier, il est nommé getDerivedStateFromProps(marquez la lettre majuscule dans les accessoires) et les paramètres sont nextProps, prevState(pas nextState): reactjs.org/docs/…
nerfologist
1
Hou la la! nous pouvons l'utiliser pour mettre à jour l'état lorsque les accessoires mis à jour sont reçus!
Aromal Sasidharan
2
Faut-il encore créer l'état initial dans le constructeur, sachant que le getDerivedStateFromPropsest toujours appelé avant le rendu initial?
bvdb
19

Vous pouvez utiliser le formulaire court comme ci-dessous si vous souhaitez ajouter tous les accessoires pour indiquer et conserver les mêmes noms.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
dacharjaya
la source
1
c'est un anti-modèle pour copier des propriétés qui ne changent jamais en état. Il est préférable de décrire explicitement les champs utilisés par votre composant.
Michael Freidgeim
5

définir les données d'état à l'intérieur du constructeur comme ceci

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

cela ne fonctionnera pas si vous définissez la méthode side componentDidMount () via les accessoires.

Krishna Kumar Jangid
la source
3

Si vous lancez directement l'état à partir des accessoires, il affichera un avertissement dans React 16.5 (5 septembre 2018)

Sujith S
la source
une idée pourquoi il avertira?
Nitin Jadhav
2
Il semble que ce soit seulement si vous utilisez state = props. Plus d'informations ici: github.com/facebook/react/pull/11658#issuecomment-419677176
maintenant le
1

Vous pouvez utiliser componentWillReceiveProps.

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

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }
Ankit Kumar Rajpoot
la source
1
componentWillReceiveProps is Deprecated ne peut pas être utilisé pour les futures versions
Vivek Ghanchi
1

VOUS DEVEZ ÊTRE PRUDENT lorsque vous initialisez à statepartir propsdu constructeur. Même s'il était propschangé pour un nouveau, l'état ne serait pas changé car le montage ne se reproduirait plus. getDerivedStateFromPropsExiste donc pour cela.

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
la source