Formularios

Los formularios son una parte fundamental de cualquier aplicación, pues son la puerta de entrada para que los usuarios puedan interactuar con la aplicación, y en React no es la excepción. Sin embargo, existe una diferencia sustancia al trabajar con formularios en React y en una tecnología web convencional, ya que React almacena la información en sus Estados, y no en una sesión del lado del servidor, como sería el caso de una aplicación web tradicional.

En React existe dos formas de administrar los controles de un formulario, controlados y no controlados, el primero permite ligar el valor de un campo al estado, mientras que el segundo permite tener un campo de libre captura, el cual no está ligado al estado o una propiedad.

tip

Nuevo concepto: Controles

El termino Controles se utiliza para llamar de forma genérica a los elementos que conforman un formulario y que el usuario puede interactuar con ellos, por ejemplo: input, radio button, checkbox, select, textarea, etc.

Controlled Components

Los componentes controlados son todos aquellos que su valor está ligado directamente al estado del componente o una propiedad (prop), lo que significa que el control siempre mostrará el valor del objeto asociado.

Para que un control sea considerado controlador (Controlled), es necesario vincular su valor con el estado o una propiedad mediante el atributo value, como podemos ver en el siguiente ejemplo.

1<input type="text" value={this.state.field} /> 

Debido a que el valor mostrado es una representación del estado o propiedad, el usuario no podrá editar el valor del control directamente. Veamos un ejemplo para comprender esto. Crearemos un nuevo archivo llamado FormTest.js y lo dejaremos de la siguiente forma:

1import React from 'react'
2import Image from 'next/image'  
3    
4class FormTest extends React.Component{  
5    
6    constructor(props){  
7    super(props)  
8    this.state = {  
9        field: "Init values"  
10    }  
11    }  
12    
13    render(){  
14    
15    return (  
16        <input type="text" value={this.state.field} />  
17    )  
18    }  
19}  
20export default FormTest  

A continuación, modificaremos el archivo App.js para mostrar el componente FormTest en el método render. No olvidemos importar el componente:

1render(){  
2	  return (  
3	    <FormTest/>  
4	  )  
5	} 

Finalmente, guardamos los cambios y actualizamos el navegador para reflejar los cambios:

Controlled Componente
Controlled Componente

Una vez actualizado el navegador, podremos ver el campo de texto con el valor que pusimos en el estado del componente, y si intentamos actualizar el valor, veremos que este simplemente no cambiará. Esto es debido a que React muestra el valor como inmutable.

Observemos en la imagen que React nos ha arrojado un warning, esta advertencia se debe a que un campo controlado, deberá definir el atributo onChange para controlar los cambios en el control, de lo contrario, este campo será de solo lectura.

Para solucionar este problema, deberemos de crear una función que tome los cambios en el control y posteriormente actualice el estado con el nuevo valor. Cuando React detecte el cambio en el estado, iniciará la actualización de la vista y los cambios será reflejados. Veamos cómo implementar esta función:

1import React from 'react'
2import Image from 'next/image'  
3import update from 'immutability-helper'  
4    
5class FormTest extends React.Component{  
6    
7    constructor(props){  
8    super(props)  
9    this.state = {  
10        field: "Init values"  
11    }  
12    }  
13    
14    updateField(e){  
15    this.setState(update(this.state, {  
16        field: {$set: e.target.value}  
17    }))  
18    }  
19    
20    render(){  
21    return (  
22        <input type="text" value={this.state.field}  
23        onChange={this.updateField.bind(this)}/>  
24    )  
25    }  
26}  
27export default FormTest  

Lo primero será definir el atributo onChange y asignarle la función updateField. Con esto, cuando se presione una tecla sobre el control, este lanzará un evento que será tratado por esta función. Cuando la función reciba el evento de cambio, actualizará el estado (línea 14) y React automáticamente actualizará la vista, cuando esto pase, el campo tomará el nuevo valor del estado.

Todos los controles funcionan exactamente igual que en HTML tradicional, sin embargo, existe dos controles que se utilizan de forma diferente, los cuales son los TextArea y Select. Analicémoslo por separado.

TextArea

La forma tradicional de utilizar un TextArea es poner el valor entre la etiqueta de apertura y cierre, como se ve en el siguiente ejemplo:

1<textarea>{this.state.field}</textarea> 

En React, para definir el valor de un TextArea se deberá utilizar el atributo value, como podemos ver en el siguiente ejemplo:

1<textarea value={this.state.field}/>

Select

El control Select cambia solo la forma en que seleccionamos el valor por default, pues en HTML tradicional solo deberemos utilizar el atributo selected sobre el valor por default, veamos un ejemplo:

1<select>  
2    <option value="volvo">Volvo</option>  
3    <option value="saab">Saab</option>  
4    <option value="vw">VW</option>  
5    <option value="audi" selected>Audi</option>  
6</select> 

En React, cambiamos el atributo selected sobre la etiqueta option, por el atributo value sobre la etiqueta select, el cual deberá coincidir con el value del option, veamos un ejemplo:

1<select value="audi">  
2    <option value="volvo">Volvo</option>  
3    <option value="saab">Saab</option>  
4    <option value="vw">VW</option>  
5    <option value="audi">Audi</option>  
6</select>

Uncontrolled Components

Los componentes no controlados son aquellos que no están ligados al estado o propiedades. Por lo general deberemos evitar utilizar controles no controlados, pues se sale del principio de React, aunque esto no significa que no debamos utilizarlos nunca, pues existen escenarios concretos en donde pueden resultar útiles, como lo son formularios grandes, donde no requerimos realizar acción alguna hasta que se manda el formulario.

Para crear un componente no controlado, están simple como definir el control sin el atributo value. Al no definir este atributo, React sabrá que el valor de este control es libre y permitirá su edición sin necesidad de crear una función que controle los cambios en el control. Para analizar esto, modifiquemos el método render del componente FormTest para que quede de la siguiente manera.

1render(){  
2    return (  
3    <div>  
4        <input type="text" value={this.state.field}  
5        onChange={this.updateField.bind(this)}/>  
6        <br/>  
7        <input type="text" name="field2" defaultValue="Init Value 2" />  
8    </div>  
9    )  
10} 

Otro de las peculiaridades de React es que ofrece el atributo defaultValue para establecer un valor por default, y así poder inicializar el control con un texto desde el comienzo. También será necesario utilizar el atributo name, pues será la forma en que podremos recuperar el valor del campo al momento de procesar el envío.

Una vez aplicados los cambios, actualizamos el valor del control y presionamos el botón submit para que nos arroje en pantalla el valor capturado

Probando los controles no controlados.
Probando los controles no controlados.

Enviar el formulario

Ahora bien, si lo que queremos hacer es recuperar los valores del control al momento de mandar el formulario, deberemos encapsular los controles dentro de un form. Regresemos al archivo FormTest y actualicemos la función render para que sea de la siguiente manera:

1render(){  
2    return (  
3    <div>  
4        <input type="text" value={this.state.field}  
5        onChange={this.updateField.bind(this)}/>  
6        <br/>  
7        <form onSubmit={this.submitForm.bind(this)} >  
8        <input type="text" name="field2" />
9        <br/>  
10        <button type="submit">Submit</button>  
11        </form>  
12    </div>  
13    )  
14}

Adicional, agregaremos la función submitForm:

1submitForm(e){  
2    alert(this.state.field)  
3    alert(e.target.field2.value)  
4    e.preventDefault();  
5} 

Existen dos variantes para recuperar los valores de un control. Si está controlado, solo tendremos que hacer referencia a la propiedad del estado al que está ligado el campo (línea 2), por otra parte, si el campo no es controlado, entonces deberemos recuperar el valor del campo mediante su tributo name, como lo vemos en la línea 3.

tip

preventDefault function

La función e.preventDefault previene que el navegador mande el formulario al servidor, lo que provocaría que el navegador se actualice y nos haga un reset del estado del componente.

Debido a que React trabajo por lo general con AJAX, es importante impedir que el navegador actualice la página, pues esto provocaría que los compontes sean cargados de nuevo y nos borre los estados. Es por eso la importancia de utilizar la función preventDefault.

Acerca de este libro

Aplicaciones reactivas con React, NodeJS & MongoDB

Todo lo que acabas de ver en este artículo es solo una pequeña parte del libro Aplicaciones reactivas con React, NodeJS & MongoDB, El libro más completo en español para aprender a crear aplicaciones web completas con las tecnologías más potentes de la actualidad, desde el Frontend con React, hasta el Backend con un poderoso API REST con NodeJS y Express y persistiendo todo en MongoDB. te invito a que veas mi libro:

Ver libro
Todos los derechos reservados ©
Reactive programming
LinkedinYoutubeTwitterFacebook

© 2021, Copyright - Oscar Blancarte. All rights reserved.