Reaccionar componente inicializar estado desde accesorios

205

En React, ¿hay alguna diferencia real entre estas dos implementaciones? Algunos amigos me dicen que el primer componente es el patrón, pero no veo por qué. El segundo componente parece más simple porque el renderizado se llama solo una vez.

Primero:

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;

Segundo:

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;

Actualización: cambié setState () a this.state = {} (gracias Joe), sin embargo, todavía no veo la diferencia. ¿Es uno mejor que otro?

Levy Moreira
fuente
10
¿Por qué estás almacenando tus accesorios en el estado? En su lugar, debe usar sus accesorios directamente, en lugar de almacenar en caché un valor. Eche un vistazo a Por qué configurar Props como estado en React.js es blasfemia y Props en getInitialState es un antipatrón .
Aurora0001
12
Un ejemplo: un componente que se puede alternar (por ejemplo, un popover o un cajón). El padre sabe si el componente debe comenzar abierto o cerrado; el componente en sí puede saber si está abierto o no en un momento determinado. En ese caso, creo que this.state = { isVisible: props.isVisible }tiene sentido. Depende de cómo la aplicación distribuya el estado de la IU.
Joe
2
Debería leer este medio.com/@justintulk/…
FDisk
55
En 2017, Facebook demuestra el uso de accesorios para establecer el estado inicial en su documentación: reactjs.org/docs/react-component.html#constructor
Rohmer
1
@ Aurora0001 En una situación en la que necesita manejar un formulario, diga un formulario de edición que haga solicitudes de red por sí mismo, pero necesita inicializar las entradas con valores que vendrían como accesorios para ese componente. Para mantener la forma dinámica, esos valores deben mantenerse en estado.
Eric McWinNEr

Respuestas:

196

Cabe señalar que es un antipatrón para copiar propiedades que nunca cambian al estado (solo acceda a .props directamente en ese caso). Si tiene una variable de estado que eventualmente cambiará pero comienza con un valor de .props, ni siquiera necesita una llamada al constructor; estas variables locales se inicializan después de una llamada al constructor del padre:

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

Esta es una taquigrafía equivalente a la respuesta de @joews a continuación. Parece que solo funciona en versiones más recientes de los transpiladores es6, he tenido problemas con él en algunas configuraciones de paquetes web. Si esto no funciona para usted, puede intentar agregar el complemento babel babel-plugin-transform-class-properties, o puede usar la versión no abreviada de @joews a continuación.

Zane Hooper
fuente
1
¿Puedes explicar más en qué se diferencia tu respuesta de @joews answer?
Jalal
3
Se agregó "Puede omitir la llamada del constructor si todo lo que está haciendo es establecer variables".
Zane Hooper
3
Si no funciona, probablemente necesite instalar este complemento de babel "babel-plugin-transform-class-properties".
Faheem
2
No es un antipatrón inicializar el estado desde los accesorios si se entiende que el estado no depende de los accesorios después de la inicialización. Si está tratando de mantener los dos sincronizados, eso es un antipatrón.
Yatrix
1
@ ak85 es la misma sintaxis pero usarías this.state en su lugar. Esta sintaxis es solo una sintaxis abreviada para establecer el estado durante el proceso de construcción de la clase (y también se puede usar para variables distintas del estado)
Zane Hooper
137

No necesita llamar setStatea un componente constructor; es idiomático configurarlo this.statedirectamente:

class FirstComponent extends React.Component {

  constructor(props) {
    super(props);

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

Ver React docs - Agregar estado local a una clase .

No hay ninguna ventaja en el primer método que describe. Resultará en una segunda actualización inmediatamente antes de montar el componente por primera vez.

joews
fuente
44
Buena respuesta. Vale la pena señalar que esto es solo para establecer el estado inicial; aún debe usarlo setStatesi lo muta en cualquier otro punto; de lo contrario, es posible que los cambios no se procesen.
Aurora0001
Gracias de nuevo jowes, segundo la documentación facebook.github.io/react/docs/…
Levy Moreira
(lo siento, presiono Intro ...) deberíamos usar getInitialState para establecer los accesorios en estado, en tareas más complejas, si es simple, podemos usar this.props en el render, ¿correcto?
Levy Moreira
1
En una nota marginal: uso super(props)en el constructor. Discusión sobre SO
cutemachine
2
La sugerencia de Joe funciona en la mayoría de los casos, pero tenga cuidado al enviar accesorios directamente a este estado. Copiar accesorios a this.state es en realidad una fuente única de verdad ( medium.com/react-ecosystem/… ). Además, Dan Abramov una vez sugirió no almacenar los valores de los accesorios en el estado. ( twitter.com/dan_abramov/status/749710501916139520/photo/1 ).
Hiroki
33

Actualización para React 16.3 alpha introducida static getDerivedStateFromProps(nextProps, prevState)( docs ) como reemplazo de componentWillReceiveProps.

getDerivedStateFromProps se invoca después de que se instancia un componente y cuando recibe nuevos accesorios. Debería devolver un objeto al estado de actualización, o nulo para indicar que los nuevos accesorios no requieren actualizaciones de estado.

Tenga en cuenta que si un componente principal hace que su componente se vuelva a representar, se llamará a este método incluso si los accesorios no han cambiado. Es posible que desee comparar valores nuevos y anteriores si solo desea manejar los cambios.

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

Es estático, por lo tanto, no tiene acceso directo a this(sin embargo, sí tiene acceso prevState, lo que podría almacenar cosas que normalmente están unidas a, thispor ejemplo refs)

editado para reflejar la corrección de @ nerfologist en los comentarios

Ashley Coolman
fuente
3
Solo para aclarar, se llama getDerivedStateFromProps(marque la letra mayúscula en Props) y los parámetros son nextProps, prevState(no nextState): reactjs.org/docs/…
nerfólogo
1
¡Guauu! ¡podemos usar esto para actualizar el estado cuando se reciben accesorios actualizados !
Aromal Sasidharan
2
¿Todavía tenemos que crear el estado inicial en el constructor, considerando que getDerivedStateFromPropssiempre se llama antes del renderizado inicial?
bvdb
19

Puede usar el formulario corto como se muestra a continuación si desea agregar todos los accesorios para indicar y conservar los mismos nombres.

constructor(props) {
    super(props);
    this.state = {
       ...props
    }
    //...
}
dacharjaya
fuente
1
Es un antipatrón para copiar propiedades que nunca cambian al estado. Es mejor describir explícitamente qué campos usa su componente.
Michael Freidgeim
5

establecer los datos de estado dentro del constructor como este

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

no funcionará si configura el método de componente lateralDidMount () a través de accesorios.

Krishna Kumar Jangid
fuente
3

Si inicia directamente el estado desde los accesorios, se mostrará una advertencia en React 16.5 (5 de septiembre de 2018)

Sujith S
fuente
alguna idea de por qué avisará?
Nitin Jadhav
2
Parece que es solo si lo usas state = props. Más información aquí: github.com/facebook/react/pull/11658#issuecomment-419677176
ahora el
1

Puede usar componentWillReceiveProps.

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

    componentWillReceiveProps(nextProps){
        this.setState({ productdatail: nextProps.productdetailProps })
    }
Ankit Kumar Rajpoot
fuente
1
componentWillReceiveProps está en desuso No se puede usar para futuras versiones
Vivek Ghanchi
1

DEBE TENER CUIDADO cuando inicializa statedesde el propsconstructor. Incluso si se propscambia a uno nuevo, el estado no cambiará porque el montaje nunca volverá a ocurrir. Entonces getDerivedStateFromPropsexiste para eso.

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
fuente