Como en todas las cosas, la primera vez que usamos algo estamos expuestos a cometer errores. En este artículo vamos a hablar de los tres errores mas cómunes cuando se tiene poca experiencia trabajando con JavaScript y React.
Acerca de los conceptos usados en este artículo:
Personalmente hay conceptos que no me gusta traducir al inglés y no lo hago por variados motivos que puedes leer acá. En este caso, hago un listado de las palabras que usaré sin traducir y su significado para que pueda ser mas claro al momento de leer.
- state: Estado. En React el término de state se refiere a un objeto que almacena los datos que definen el estado de la aplicación.
- this: Esto. En JavaScript se puede acceder a this para hacer referencia al objeto en el contexto donde fue ejecutado.
12345class Pelota {constructor() {this.color= 'red';}} - undefined: Indefinido. En JavaScript una variable o expresión que no tiene un valor asignado en realidad tiene asignado el valor “undefined”.
12let a;console.log(a) // Esto mostrará "undefined" - transpiler: Transpilador. Es un tipo de compilador que se encarga de convertir código de una forma a otra. En este caso hablaremos de un tipo muy usado para convertir código JavaScript de ES6 a ES5.
- bind: Enlazar. En este caso lo usamos para enlazar el contexto de this a una función.
3 típicos errores en React y cómo evitarlos
Vamos a hablar de los tres errores mas cómunes cuando se tiene poca experiencia trabajando con JavaScript y React.
- Los datos que se almacenan en el state
- Los componentes controlados y sus valores
- Perder el contexto de this
1. Los datos que se almacenan en el state
La confusión acerca del state cuando apenas estas aprendiendo React es muy común, así es que no te frustes, todos estuvimos ahí, y así como muchos lo superamos, ¡tu también lo harás!
Este error surge porque no es muy claro que cosas deben o no guardarse en el state, ya que a primera vista, se puede entender que los props dependen del state, pero no es así.
El tip para evitar estos errores en React es:
Imagina tu aplicación como una máquina de estados, de modo que cuando ocurre un cambio, eso te lleva a un nuevo estado de la aplicación.
Bien, pues los state son eso, datos o características que cuando cambian te llevan a un nuevo estado de tu aplicación.
Cualquier otra cosa que no afecta el estado de la aplicación no es un state, y aunque lo quieras pasar a tus componentes como prop no tendría que estar guardado en el state, puede ser un objeto aparte.
Ejercicio:
Estas construyendo una aplicación (un formulario) que con base a las entradas del usuario despliega texto autogenerado.
- ¿Qué cosas guardarías en el state?
- El texto que se va generando, ¿en donde lo guardarías?
2. Los componentes controlados y sus valores
Un componente controlado es aquel que para mostrar información la recibe de un proceso exterior.
En una buena práctica, los formularios se pueden utilizar como componentes controlados para así tener control sobre las entradas del usuario y posibles procesos que se puedan hacer en ellos.
Un error muy común cuando se trabaja con componentes controlados es enviar la propiedad value con valor de undefined. Esto hará entender a React que no deseas controlar el componente.
El tip para evitar estos errores en React es:
Para componentes controlados que aún no tiene un valor “inicial”, lo ideal es enviar una cadena vacía o un cero según sea el caso, pero jamás undefined.
Ejercicio:
En el siguiente código:
- ¿Cuál componente es controlado?
- ¿Cuál es el componente no controlado?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class Formulario1 extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } render() { return ( <form onSubmit={this.handleSubmit}> <label htmlFor="name">Name</label> <input id="name" type="text" idvalue={this.state.value} onChange={this.handleChange} /> </form> ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class Formulario2 extends React.Component { constructor(props) { super(props); this.input = React.createRef(); } render() { return ( <form onSubmit={this.handleSubmit}> <label htmlFor="name">Name</label> <input id="name" type="text" ref={this.input} onChange={this.handleChange} /> </form> ); } } |
3. Perder el contexto de this
¿Te ha pasado que mandas this.unMetodo a un componente hijo, o que tienes un método dentro de tu componente pero no funciona como esperas?
Aunque este no es un error cómo tal de React, es común que muchos programadores novatos con Javascript (y también muchos con experiencia) cometan el error de “perder” el contexto de this.
El tip para evitar estos errores en React y JavaScript es:
En el constructor de tu clase debes enlazar (bind) el valor de this que se refiere a la clase a tu método.
La otra opción, es convertir tu método a una función flecha (arrow function) para que así, el contexto de this aplique en la creación y no en la ejecución. Esta solución no es recomendada ya que sin un transpiler de ES6 a ES5 no funcionará en todos los navegadores.
Ejercicio:
En el siguiente código
- ¿En cuál de los tres casos el contexto de this en el método handleChange() hará referencia al método y no a la propiedad state de la clase?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Formulario1 extends React.Component { constructor(props) { super(props); this.state = {value: ''}; } handleChange(event) { this.setState({value: event.target.value}); } render() { return ( <form onSubmit={this.handleSubmit}> <label htmlFor="name">Name</label> <input id="name" type="text" idvalue={this.state.value} onChange={this.handleChange} /> </form> ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class Formulario2 extends React.Component { constructor(props) { super(props); this.state = {value: ''}; this.handleChange = this.handleChange.bind(this); } handleChange(event) { this.setState({value: event.target.value}); } render() { return ( <form onSubmit={this.handleSubmit}> <label htmlFor="name">Name</label> <input id="name" type="text" idvalue={this.state.value} onChange={this.handleChange} /> </form> ); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
class Formulario3 extends React.Component { constructor(props) { super(props); this.state = {value: ''}; } handleChange: (event) => { this.setState({value: event.target.value}); } render() { return ( <form onSubmit={this.handleSubmit}> <label htmlFor="name">Name</label> <input id="name" type="text" idvalue={this.state.value} onChange={this.handleChange} /> </form> ); } } |
Respuestas para los errores mas comunes en React:
- ¿Qué cosas guardarías en el state? Los valores que el usuario ingresa en los inputs del formulario, ya que estos cambian el estado actual de la aplicación, sin embargo el texto generado no cambia el estado del funcionamiento de la aplicación. Es decir, si cambio el texto generado, la aplicación sigue en el mismo punto de ejecución.
- El texto que se va generando, ¿en donde lo guardarías? En una nueva propiedad de mi componente, puede ser por ejemplo algo como this.textoGenerado, ya que estos se pueden actualizar automático con base a los cambios del state. Ese objeto se puede entonces mandar por props para que se renderee.
- ¿Cuál componente es controlado? El formulario1 es controlado, ya que el valor para el input se envia desde el state.
- ¿Cuál es el componente no controlado? El formulario2 es no controlado ya que el valor del input no se envia desde el state, y para manejar su valor se tiene que usar ref.
- ¿En cuál de los tres casos el contexto de this en el método handleChange() hará referencia al método y no a la propiedad state de la clase? En el formulario2 si se mantiene el contexto de la clase ya que en el constructor se hizo bind de this para ese método. Asímismo, en el formulario3 se mantiene el contexto de la clase ya que se esta utilizando una función flecha.