Il componente React inizializza lo stato dagli oggetti di scena


205

In React, ci sono differenze reali tra queste due implementazioni? Alcuni amici mi dicono che il FirstComponent è il modello, ma non vedo perché. SecondComponent sembra più semplice perché il rendering viene chiamato solo una volta.

Primo:

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;

Secondo:

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;

Aggiornamento: ho cambiato setState () in this.state = {} (grazie joews), tuttavia non vedo ancora la differenza. Uno è meglio dell'altro?


10
Perché stai conservando i tuoi oggetti di scena nello stato? Dovresti invece usare direttamente i tuoi oggetti di scena, piuttosto che memorizzare un valore nella cache. Leggi perché impostare i puntelli come stato in React.js è blasfemia e i puntelli in getInitialState è un anti-schema .
Aurora0001,

12
Un esempio: un componente commutabile (ad esempio un popover o un cassetto). Il genitore sa se il componente deve iniziare aperto o chiuso; il componente stesso può sapere se è aperto o meno in un determinato momento. In quel caso penso this.state = { isVisible: props.isVisible }abbia senso. Dipende da come l'app distribuisce lo stato dell'interfaccia utente.
joews,

2
Dovresti leggere questo medium.com/@justintulk/…
FDisk il

5
Nel 2017, Facebook dimostra di aver usato gli oggetti di scena per impostare lo stato iniziale nella loro documentazione: reazionejs.org/docs/react-component.html#constructor
Rohmer il

1
@ Aurora0001 Cosa succede in una situazione in cui è necessario gestire un modulo, dire un modulo di modifica che farebbe richieste di rete da solo ma è necessario inizializzare gli input con valori che verrebbero come oggetti di scena a quel componente. Per mantenere dinamico il modulo, tali valori devono essere mantenuti in stato.
Eric McWinNEr,

Risposte:


196

Va notato che è un anti-pattern per copiare proprietà che non cambiano mai nello stato (basta accedere a .props direttamente in quel caso). Se hai una variabile di stato che alla fine cambierà ma inizia con un valore di .props, non hai nemmeno bisogno di una chiamata del costruttore - queste variabili locali vengono inizializzate dopo una chiamata al costruttore del genitore:

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

Questa è una scorciatoia equivalente alla risposta di @joews di seguito. Sembra funzionare solo su versioni più recenti dei transpiler es6, ho avuto problemi con alcune configurazioni di webpack. Se questo non funziona per te, puoi provare ad aggiungere il plug-in babel babel-plugin-transform-class-propertiesoppure puoi utilizzare la versione non abbreviata di @joews di seguito.


1
puoi spiegare di più in che modo la tua risposta è diversa dalla risposta di @joews?
Jalal,

3
Aggiunto "È possibile saltare la chiamata del costruttore se tutto ciò che si sta facendo è impostare le variabili."
Zane Hooper,

3
Se non funziona, probabilmente dovrai installare questo plugin babel "babel-plugin-transform-class-properties".
Faheem,

2
Non è un anti-schema per inizializzare lo stato dai puntelli se si comprende che lo stato non si basa sui puntelli dopo l'inizializzazione. Se stai cercando di mantenere i due sincronizzati, questo è un anti-pattern.
Yatrix,

1
@ ak85 è la stessa sintassi ma invece useresti this.state. Questa sintassi è solo una sintassi abbreviata per impostare lo stato durante il processo di costruzione della classe (e può essere utilizzata anche per variabili diverse dallo stato)
Zane Hooper,

137

Non è necessario chiamare setStateun componente constructor- è idiomatico impostare this.statedirettamente:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

Vedi Documenti di React - Aggiunta di stato locale a una classe .

Non vi è alcun vantaggio nel primo metodo che descrivi. Ciò comporterà un secondo aggiornamento immediatamente prima del montaggio del componente per la prima volta.


4
Buona risposta. Vale la pena notare che questo serve solo per impostare lo stato iniziale; devi comunque usarlo setStatese lo muti in qualsiasi altro punto, altrimenti le modifiche potrebbero non essere visualizzate.
Aurora0001,

Grazie ancora jowes, secondo la documentazione facebook.github.io/react/docs/…
Levy Moreira,

(scusate, premo invio ..) dovremmo usare getInitialState per impostare gli oggetti di scena su, in compiti più complessi, se è semplice possiamo semplicemente usare this.props nel rendering, giusto?
Levy Moreira,

1
Su una nota marginale: usare super(props)nel costruttore. Discussione su SO
cutemachine,

2
Il suggerimento di joews funziona nella maggior parte dei casi, ma fai attenzione a inviare oggetti di scena direttamente a this.state. Copiare oggetti di scena su this.state è in realtà una singola fonte di verità ( medium.com/react-ecosystem/… ). Inoltre, una volta Dan Abramov ha suggerito di non memorizzare i valori degli oggetti di scena nello stato. ( twitter.com/dan_abramov/status/749710501916139520/photo/1 ).
Hiroki,

33

Aggiornamento per React 16.3 alpha introdotto static getDerivedStateFromProps(nextProps, prevState)( documenti ) in sostituzione di componentWillReceiveProps.

getDerivedStateFromProps viene richiamato dopo un'istanza di un componente e quando riceve nuovi oggetti di scena. Dovrebbe restituire un oggetto per aggiornare lo stato, oppure null per indicare che i nuovi oggetti di scena non richiedono alcun aggiornamento di stato.

Si noti che se un componente padre provoca il rendering del componente, questo metodo verrà chiamato anche se gli oggetti di scena non sono stati modificati. È possibile che si desideri confrontare i valori nuovi e precedenti se si desidera gestire solo le modifiche.

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

È statico, quindi non ha accesso diretto a this(tuttavia ha accesso a prevState, che potrebbe archiviare cose normalmente collegate ad thises. refs)

modificato per riflettere la correzione di @ nerfologist nei commenti


3
Giusto per chiarire, è chiamato getDerivedStateFromProps(segna la lettera maiuscola in Puntelli) e i parametri sono nextProps, prevState(non nextState): reagjs.org/docs/…
nerfologo il

1
Wow! possiamo usarlo per aggiornare lo stato alla ricezione di oggetti di scena aggiornati !
Aromal Sasidharan,

2
Dobbiamo ancora creare lo stato iniziale nel costruttore, considerando che getDerivedStateFromPropsviene sempre chiamato prima del rendering iniziale?
bvdb

19

Puoi usare la forma abbreviata come sotto se vuoi aggiungere tutti gli oggetti di scena per dichiarare e conservare gli stessi nomi.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}

1
è un anti-pattern per copiare proprietà che non cambiano mai allo stato. È meglio descrivere esplicitamente quali campi vengono utilizzati dal componente.
Michael Freidgeim,

5

impostare i dati di stato all'interno del costruttore in questo modo

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

non funzionerà se si imposta il metodo side componentDidMount () tramite i puntelli.




1

È possibile utilizzare componentWillReceiveProps.

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

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }

1
componentWillReceiveProps è obsoleto non può essere utilizzato per le versioni future
Vivek Ghanchi

1

Devi essere attento quando esegui l'inizializzazione stateda propsnel costruttore. Anche se propscambiato in uno nuovo, lo stato non verrebbe modificato perché il mount non si ripeterà mai più. Quindi getDerivedStateFromPropsesiste per quello.

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} /> 
        );
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.