¡El constructor está muerto, viva el constructor!

Despídase del constructor de clase medieval en sus componentes React.

Foto de Samuel Zeller en Unsplash

Aunque los componentes de función sin estado (SAC) son una herramienta útil en su arsenal, los componentes de clase ES6 siguen siendo la manera de facto de escribir componentes Reaccionar que utilizan ganchos de estado o de ciclo de vida.

Un componente hipotético de la clase ES6 podría verse más o menos así (simplificado en exceso sin verificación de errores, por supuesto).

 clase Foo extends Componente { 
constructor (accesorios) {
super (apoyos);
this.state = {cargando: verdadero};
}
 async componentDidMount () { 
const data = aguardar loadStuff ();
this.setState ({carga: falso, datos});
}
 render () { 
const {carga, datos} = this.state;
regreso (
{cargando ? <Cargando />: <Ver {... datos} />}
);
}
}

Inicializamos nuestro state en el constructor , cargamos de forma asíncrona nuestros datos en componentDidMount y representamos nuestro componente View función del estado de loading . Un patrón bastante estándar, al menos para mí, si has estado siguiendo mi trabajo.

Propiedades de clase

A todos nos han enseñado que el constructor es donde inicializamos nuestras propiedades de la instancia, state en este caso. Y si te dices a ti mismo, "¡Exactamente!", Entonces estarías absolutamente en lo cierto … si no fuera por la próxima propuesta de propiedades ES.next class , actualmente en la etapa 3.

Con él ahora podemos definir propiedades de clase directamente, así.

 clase Foo extends Componente { 
state = {cargando: verdadero};
...
}

Babel transpilará su código y agregará un constructor detrás de escena. Aquí está la salida de Babel cuando transpilemos el fragmento de código anterior.

Tenga en cuenta que Babel en realidad está pasando todos los argumentos, no solo los props , a super . También está tomando el valor de retorno de super y devolvérselo a la persona que llama. Ambos pueden ser un poco exagerados, pero exactamente lo que debería estar haciendo.

Todavía hay un constructor, simplemente no lo ves.

Métodos de enlace

Otra razón por la que nos enseñaron a usar el constructor es por métodos de enlace a this , como tal.

 clase Foo extends Componente { 
constructor (accesorios) {
super (apoyos);
this.myHandler = this.myHandler.bind (esto);
}
 myHandler () { 
// algún código aquí que haga referencia a esto
}
...
}

Algunas personas ignoran todo esto al asignar una expresión de función a una propiedad de clase, pero esa es una historia completamente diferente. Lea más sobre esto en mi otro artículo de ES6 React Classes Desmitificando el uso de la memoria usando ES6 React Classes .

Desmitificando el uso de la memoria usando ES6 React Classes
¿Cuál es más eficiente? ¿Enlazar en el constructor, o usar una función de flecha como propiedad de clase? medium.com

Supongamos por un momento que usted está en el bind campo (e incluso si no lo eres, toleradme). Tendremos que enlazar en el constructor , ¿verdad? No necesariamente. Podemos hacer lo mismo que hicimos para las propiedades de clase anteriores.

 clase Foo extends Componente { 
myHandler = this.myHandler.bind (esto);
 myHandler () { 
// algún código aquí que haga referencia a esto
}
...
}

Inicializando el estado con accesorios

¿Qué ocurre cuando necesita derivar su state inicial de los props , por ejemplo, para inicializar un valor predeterminado? Seguramente necesitamos el constructor para eso?

 clase Foo extends Componente { 
constructor (accesorios) {
super (apoyos);
this.state = {
color: this.props.initialColor
};
}
 render () { 
const {color} = this.state;
regreso (
<div>
{color}
</ div>
);
}
}

¡No! Nuevamente, ¡propiedades de clase para el rescate! Tenemos acceso tanto a this como a los props .

 clase Foo extends Componente { 
estado = {
color: this.props.initialColor
};
...
}

Obtención de datos

Tal vez necesitamos un constructor para obtener datos? Apenas. Como vimos en nuestro primer ejemplo de código, cualquier carga de datos debe hacerse en componentDidMount . Pero, ¿por qué componentDidMount ? Lo hacemos allí para que la búsqueda no se realice cuando se ejecuta el componente en el servidor, como es el caso al realizar la Representación del lado del servidor (Server Side Rendering, SSR), ya que componentDidMount no se realiza en el servidor.

Conclusión

Hemos visto que para establecer nuestro state inicial, ya no necesitamos un constructor (o cualquier otra propiedad de instancia para el caso). Tampoco lo necesitamos para métodos de enlace a this . Lo mismo para establecer el state inicial de los props . Y definitivamente nunca obtendríamos datos en el constructor .

¿Por qué entonces necesitaríamos alguna vez el constructor en un componente Reaccionar?

Bueno … tú no.

[Sin embargo … Si encuentra un caso de uso oscuro donde necesita inicializar algo en un componente, tanto del lado del cliente como del lado del servidor, todavía tiene una salida. Siempre hay componentWillMount . Internamente, React llama a este enlace justo después de "actualizar" la clase (que llama al constructor ) tanto en el cliente como en el servidor.]

Así que mantengo eso para los componentes de React: ¡El constructor está muerto, viva el constructor!

Otras lecturas

Bueno, no leyendo, pero Kent C. Dodds tiene un buen video tutorial sobre las propiedades de la clase que es posible que desee leer, um … observar.

Texto original em inglês.