Formularios en React, input controlados y no controlados

Juan Carlos G 2020-07-02
1
Formularios en React, input controlados y no controlados


Hola de nuevo viajero, hoy vamos a continuar con este curso de React JS y el tema que tocaremos el día de hoy es referente al Manejo de Formularios en React, este es un tema sumamente importante ya que prácticamente en toda página web vas a necesitar de al menos un formulario.

Cabe a clarar, que en este primer post veremos las formas en que podemos manejar formularios sin ocupar librerías de terceros, si este curso recibe bastante apoyo, iré complementando con algunas librerías que existen y que en algunos casos suelen ser de utilidad.

  • Si aun no has visto el capítulo anterior sobre Listas y condiciones en React, por favor revísalo para que vayas en orden y aprendas cada concepto.

 

📌 Suscríbete a mi canal y activa la campanita para que no te pierdas ningún video 🤘

 

¿Qué aprenderás en este vídeo?

  • Utilización de inputs no controlados a través de refs
  • Recuperar datos de input no controlados a través de eventos
  • Creación de inputs controlados
  • Aprenderás a desarrollar un formulario listo para agregarlo a tu proyecto
  • Conocerás una de las formas en que puedes validar los datos de tu formulario
  • Y mucho más.

 

Repositorio:

  • Este capitulo lo puedes descargar clonando el repositorio con la siguiente línea de código.
  • Y solo debes cambiarte a la rama de nombre "formularios"
  • Si no estas familiarizado con Git, descarga el código aquí.
  • Recuerda que cada capítulo estará en una rama diferente para llevar un orden

 

git clone https://github.com/EWebik/react-js.git

 

Manejo de formularios en React

El comportamiento de formularios en React es un poco diferente a otros elementos dentro del DOM que crea la librería de React, y esto se debe a que los formularios por si mismos almacenan un cierto tipo de estado.

Esto lo podemos ver claramente cuando utilizamos el tag form en HTML el cual tiene uno o mas inputs dentro de su estructura.

Cada input es capaz de almacenar información, por ejemplo, el name o el value, y después, recuperar el value a través de un identificador como el name para enviarlo al servidor a través de una API u otro medio de comunicación que tengamos con nuestro servidor.

 

Componentes controlados y no controlados

En su forma más básica los inputs dentro de un formulario los podemos manejar en una forma:

  • Controlada
  • Y no controlada

 

Inputs no controlados

Los input no controlados son una forma en que podemos manipular los componentes, esto quiere decir, que No vamos a utilizar el state de React para obtener o modificar los valores y propiedades de un form.

Entonces, para utilizar input no controlados lo podemos hacer utilizando:

  • La refs en React
  • O por eventos, tal como lo hace el evento submit en un tag form

 

Manejo de Inputs a través de Refs

Esto lo hemos visto en un capítulo anterior y solo debemos crear un referencia y a partir de ello obtener el value del input, por ejemplo:

 

class Componente extends React.Component{

  constructor(props){
    super(props);
    this.nombre = React.createRef();
    this.correo = React.createRef();
  }
  //Inputs no controlados, obteniendo datos a través de Refs
  clicRefs(evento){
    evento.preventDefault();
    console.log(this.nombre.current.value);
    console.log(this.correo.current.value);
  }

  render(){
    return(
      <form>
        <h1>{"Formularios EWebik"}</h1>
        <input type="text" refs={this.nombre} placeholder="Nombre" />
        <input type="text" refs={this.correo} placeholder="Correo" />
        <button onClick={this.clicRefs.bind(this)}>
          Enviar
        </button>
      </form>
    )
  }
}

 

El código anterior es muy similar a como lo manejamos en HTML, es una buena opción cuando tienes pocos input y no tienes que hacer grandes validaciones.

 

Manejo de Inputs a través de submit

La forma clásica del manejo de formularios es recuperar la información de cada input cuando se dispara el evento submit, esto seguramente lo has hecho en JavaScript en un login o algo por el estilo, en React lo podemos hacer de la siguiente manera.

class Componente extends React.Component{

  //Inputs no controlados, obteniendo datos a través del evento submit
  clicEventos(evento){
    evento.preventDefault();
    console.log(evento.target.value);
    console.log(evento.target.value);
  }

  render(){
    return(
      <form onSubmit={this.clicEventos}>
        <h1>{"Formularios EWebik"}</h1>
        <input type="text" placeholder="Nombre" />
        <input type="text" placeholder="Correo" />
        <button>
          Enviar
        </button>
      </form>
    )
  }
}

 

Al igual que en el caso anterior es útil cuando no se tiene que hacer validaciones complejas y son pocos inputs.

 

Ventaja y desventaja de utilizar componentes no controlados

  • Ventaja, el código es menos complejo y muy fácil de escribir.
  • Desventaja, la validación del valor de cada input por lo regular se hace hasta que el usuario lanza el evento submit.

Como puedes ver esta forma de manejo es algo rudimentaria pero es importante que la conozcas, dado que en alguna aplicación quizá te sea útil. Ahora pasemos a los input controlados que es lo que vas a utilizar prácticamente siempre.

 

Inputs controlados

Utilizar los input de una forma controlada es la forma recomendable al utilizar React, ya que que te permitirá reutilizar mucho código y podrás adherir muchas funcionalidades a tus componentes, por ejemplo, desarrollemos el siguiente formulario aplicando componentes controlados.

Formulario ejemplo en el manejo de forms en react js

 

Para pode desarrollar este formulario a través de componentes controlados, debemos crear cada uno de los componentes con su state particular.

 

Creando input tipo text controlado

Este componente utiliza el state para almacenar el valor del input y un estado de error que indicará si el usuario esta introduciendo un dato valido, en formulario de ejemplo lo utilizamos para validar que lo que ingresa es un nombre y un correo, si el código te resulta algo complicado, por favor, mira el vídeo.

class InputText extends React.Component{
  constructor(props){
    super(props);
    this.actualizarState = this.actualizarState.bind(this);
    this.state = {
      value:"",
      error:false,
      mensajeError:""
    };
  }
  actualizarState(e){
    const {name, value} = e.target;
    //console.log(name)
    //console.log(value)
    console.log(this.props.validacion(value));
    
    if(this.props.validacion(value)){
      this.setState({
        value,
        error:false,
        mensajeError:""
      });
      this.props.actualizarState({
        name,value,error:false
      });
    }else{
      this.setState({
        value,
        error:true,
        mensajeError:this.props.mensajeError
      });
      this.props.actualizarState({
        name,value,error:true
      });
    }
  }
  render(){
    return(
      <div className="componente-input">
        <label htmlFor={"id-"+this.props.name}>{this.props.label}</label>
        <input
          id={"id-"+this.props.name}
          type="text"
          name={this.props.name}
          placeholder={this.props.placeholder}
          className={this.state.error ? "border-error":""}
          onChange={this.actualizarState}/>
          {
            this.state.error ? (
            <p className="componente-input-error">{this.state.mensajeError}</p>
            ):("")
          }
      </div>
    )
  }
}

Si el usuario ingresa un dato no valido, se mostrara un párrafo en color rojo que le indica al usuario que el dato no es el correcto y debe corregir.

 

Creando input tipo Checkbox controlado

Este componente es un poco más simple ya que solo cuenta con dos estados posibles.

class InputCheckbox extends React.Component{
  constructor(props){
    super(props)
    this.actualizarState = this.actualizarState.bind(this);
    this.state={activo:false};
  }
  actualizarState(e){
    const {name, checked} = e.target;
    this.setState({activo:checked});
    this.props.actualizarState({
      name,value:checked,error:false
    })
  }
  render(){
    return(
      <div>
        <input
          id={"id-"+this.props.name}
          type="checkbox"
          name={this.props.name}
          checked={this.state.activo}
          onChange={this.actualizarState}/>
          <label htmlFor={"id-"+this.props.name}>{this.props.label}</label>
      </div>
    )
  }
}

 

Creando input tipo select controlado

Ahora veremos como agregar una lista desplegable de opciones en nuestro formulario, el siguiente checkbox nos permite agregar una lista con las opciones que nosotros deseemos, por el momento solo agregamos dos casos validos y uno no valido, por lo que se valida que el value de la opción no sea un carácter vacío.

class InputSelect extends React.Component{
  constructor(props){
    super(props)
    this.actualizarState = this.actualizarState.bind(this);
    this.state={activo:""};
  }
  actualizarState(e){
    const {name, value} = e.target;
    this.setState({value});
    this.props.actualizarState({
      name,value,error: value == "" ? true:false
    })
  }
  render(){
    return(
      <div className="componente-input">
        <label htmlFor={"id-"+this.props.name}>{this.props.label}</label>
        <select
          id={"id-"+this.props.name}
          name={this.props.name}
          onChange={this.actualizarState}>
            {
              this.props.opciones.map((opcion,index)=>(
              <option hey={index} value={opcion.value}>{opcion.texto}</option>
              ))
            }            
        </select>
      </div>
    )
  }
}

 

Creando un form con inputs controlados

Ahora que tenemos nuestros componentes básicos necesitamos crear nuestro formulario agregando cada uno de nuestros inputs controlados y lo haremos de la siguiente manera.

class Componente extends React.Component{

  constructor(props){
    super(props);
    this.submit = this.submit.bind(this);
    this.actualizarState = this.actualizarState.bind(this);
    this.state = {
      nombre:{
        value:"",
        error:true
      },
      correo:{
        value:"",
        error:true
      },
      prioridad:{
        value:false,
        error:true
      },
      opciones:{
        value:"",
        error:true
      }
    }
  }
  
  actualizarState(input){
    this.setState({
      ...this.state,
      :{
        value:input.value,
        error:input.error
      }
    }, ()=>{console.log(this.state);});
    
  }

  submit(e){
    e.preventDefault();
    console.log(this.state)
  }

  render(){
    return(
      <form onSubmit={this.submit}>
        <h1>{"Formularios EWebik"}</h1>
        <InputText
          label="Nombre"
          name="nombre"
          placeholder="Nombre"
          validacion={esNombre}
          mensajeError="Se esperaban letras"
          actualizarState={this.actualizarState} />
        
        <InputText
          label="Correo"
          name="correo"
          placeholder="Correo"
          validacion={esCorreo}
          mensajeError="Correo no valido"
          actualizarState={this.actualizarState} />

        <InputCheckbox
          name="prioridad"
          label="Prioridad"
          actualizarState={this.actualizarState} />

        <InputSelect
          name="opciones"
          label="Elige una opción:"
          actualizarState={this.actualizarState}
          opciones={[
            {value:"", texto:"Seleccione un opción..."},        
            {value:"1", texto:"Página web"},
            {value:"2", texto:"Aplicación móvil"}
            ]} />
        
        <button
          disabled={this.state.nombre.error ||
            this.state.correo.error ||
            this.state.opciones.error}
          type="submit"
          className={this.state.nombre.error ||
            this.state.correo.error ||
            this.state.opciones.error
            ? 
            "button-disable":"button"}>
          Enviar
        </button>
      </form>
    )
  }
}

ReactDOM.render(
  <Componente/>,
  document.getElementById('root')
);

En este componente:

  • Llamamos cada input controlado y lo inicializamos
  • Creamos una validación para cada InputText
  • Tenemos un state que almacena el valor de cada input junto con su estado de error
  • Si un input tiene un error, el botón de envió se mantiene disabled para no enviar datos erroneos
  • Declaramos un función actualizarState la cual recibirá el valor de cada componente del formulario y actualizará el state
  • Por ultimo tenemos una función submit, donde tenemos datos validos y podemos enviarlos a una API o a otro lugar según el tipo de tu aplicación.

Finalmente te dejo el código CSS del formulario, realmente es muy básico y no utilice una paleta de colores, así que puedes modificarlo y mejorarlo antes de utilizarlo en tu proyecto.


.componente-input{
  display: flex;
  flex-direction: column;
  margin: 10px 0px;
}
.componente-input label{
  margin: 5px 0px;
  font-size: 18px;
}
.componente-input input
,.componente-input select{
  height: 45px;
  font-size: 18px;
}
.componente-input-error{
  color: red;
  font-size: 16px;
}
.border-error{
  border: 1px solid red;
}
.button{
  background-color: royalblue;
  padding: 10px;
  font-weight: bold;
  font-size: 18px;
  color: #fff;
}
.button-disable{
  background-color: darkgray;
  padding: 10px;
  font-weight: bold;
  font-size: 18px;
  color: #fff;
}

 

Espero que esta clase te haya sido de gran ayuda, si te ha gustado suscríbete a mi canal de YouTube y comparte para que llegue a más personas que se les dificulta adquirir un corso de React y realmente tengan ganas de aprender, nos vemos en el próximo post.

 



https://ewebik.com

Juan Carlos G

Electrónica y diseño web


Durante años he desarrollado plataformas dedicadas al rastreo satelital y varios sitios web que se encuentran en la primera página de Google, y hoy quiero compartir contigo lo que se en tecnologías como Node JS, PHP, C# y Bases de datos, si quieres apoyarme sígueme en mis redes sociales y suscríbete a mi canal de YouTube.

@Puedes seguirme en mis redes

📌 Suscríbete 🤘