16-formulario-sss- levantar el estado

 

Tutorial: Formularios en React - Manejo de Inputs馃摑 Conceptos B谩sicos de Formularios en React

En React, los formularios se manejan de forma diferente a HTML puro. React controla los datos del formulario a trav茅s del estado (state).

馃幆 Ejemplo 1: Input B谩sico Controlado

import React, { useState } from 'react';


function FormularioBasico() {

  // 1. Creamos el estado para almacenar el valor del input

  const [texto, setTexto] = useState('');

  // 2. Funci贸n para manejar los cambios en el input

  const manejarCambio = (evento) => {

    // event.target.value contiene el nuevo valor

    setTexto(evento.target.value);

  };

  // 3. Funci贸n para manejar el env铆o del formulario

  const manejarEnvio = (evento) => {

    evento.preventDefault(); // Evita que la p谩gina se recargue

    alert(`Texto enviado: ${texto}`);

    setTexto(''); // Limpiamos el input despu茅s de enviar

  };


  return (

    <form onSubmit={manejarEnvio}>

      <label htmlFor="miInput">

        Escribe algo:

      </label>

      

      {/* Input controlado por React */}

      <input

        id="miInput"

        type="text"

        value={texto} // El valor viene del estado

        onChange={manejarCambio} // Actualiza el estado cuando cambia

        placeholder="Escribe aqu铆..."

      />

      

      <button type="submit">

        Enviar

      </button>

      {/* Mostramos el valor actual en tiempo real */}

      <p>Texto actual: {texto}</p></form>);

}export default FormularioBasico;

馃攳 Explicaci贸n Paso a Paso

Paso 1: Crear el Estado

javascript

const [texto, setTexto] = useState('');

  • texto: Variable que almacena el valor actual (string vac铆o inicialmente)

  • setTexto: Funci贸n para actualizar el valor

Paso 2: Input Controlado

jsx

<input

  value={texto}

  onChange={manejarCambio}

/>

  • value={texto}: El input muestra lo que hay en el estado

  • onChange={manejarCambio}: Cuando el usuario escribe, se ejecuta manejarCambio

Paso 3: Funci贸n de Cambio

javascript

const manejarCambio = (evento) => {

  setTexto(evento.target.value);

};

  • evento.target.value: Contiene el nuevo texto escrito por el usuario

  • setTexto(): Actualiza el estado con el nuevo valor


馃搳 Ejemplo 2: Input con Validaci贸n

import React, { useState } from 'react';


function FormularioConValidacion() {

  const [email, setEmail] = useState('');

  const [error, setError] = useState('');


  const manejarCambioEmail = (e) => {

    const valor = e.target.value;

    setEmail(valor);

    

    // Validaci贸n simple de email

    if (valor && !valor.includes('@')) {

      setError('Debe contener @');

    } else {

      setError('');

    }

  };


  const manejarEnvio = (e) => {

    e.preventDefault();

    if (!error && email) {

      alert(`Email v谩lido: ${email}`);

      setEmail('');

    } else {

      alert('Corrige el email primero');

    }

  };


  return (

    <form onSubmit={manejarEnvio} style={{ padding: '20px' }}>

      <h3>Registro de Email</h3>

      

      <div>

        <label>

          Tu email:

          <input

            type="email"

            value={email}

            onChange={manejarCambioEmail}

            placeholder="ejemplo@correo.com"

            style={{

              marginLeft: '10px',

              padding: '8px',

              border: error ? '2px solid red' : '1px solid gray'

            }}

          />

        </label>

      </div>

      

      {/* Mostrar error si existe */}

      {error && <p style={{ color: 'red' }}>{error}</p>}

      

      {/* Mostrar el email en tiempo real */}

      <p>Email ingresado: {email || '(vac铆o)'}</p>

      

      <button 

        type="submit"

        disabled={!!error || !email}

        style={{

          padding: '10px 20px',

          backgroundColor: error || !email ? '#ccc' : '#4CAF50',

          color: 'white',

          border: 'none',

          cursor: error || !email ? 'not-allowed' : 'pointer'

        }}

      >

        Registrarse

      </button>

    </form>

  );

}


export default FormularioConValidacion;

馃帹 Ejemplo 3: Input con Caracter铆sticas Adicionales

jsx

import React, { useState } from 'react';


function InputAvanzado() {

  const [usuario, setUsuario] = useState({

    nombre: '',

    contrasena: '',

    mostrarPassword: false

  });


  const manejarCambio = (e) => {

    const { name, value } = e.target;

    setUsuario(prev => ({

      ...prev,

      [name]: value

    }));

  };


  const toggleMostrarPassword = () => {

    setUsuario(prev => ({

      ...prev,

      mostrarPassword: !prev.mostrarPassword

    }));

  };


  const manejarEnvio = (e) => {

    e.preventDefault();

    console.log('Usuario:', usuario);

    alert(`Nombre: ${usuario.nombre}\nContrase帽a oculta por seguridad`);

  };


  return (

    <form onSubmit={manejarEnvio} style={styles.formulario}>

      <h2>Registro de Usuario</h2>

      

      {/* Input para nombre */}

      <div style={styles.grupo}>

        <label style={styles.label}>

          Nombre completo:

        </label>

        <input

          name="nombre"

          type="text"

          value={usuario.nombre}

          onChange={manejarCambio}

          placeholder="Tu nombre"

          style={styles.input}

          maxLength={50}

        />

        <small style={styles.contador}>

          {usuario.nombre.length}/50 caracteres

        </small>

      </div>

      

      {/* Input para contrase帽a */}

      <div style={styles.grupo}>

        <label style={styles.label}>

          Contrase帽a:

        </label>

        <div style={{ display: 'flex', alignItems: 'center' }}>

          <input

            name="contrasena"

            type={usuario.mostrarPassword ? "text" : "password"}

            value={usuario.contrasena}

            onChange={manejarCambio}

            placeholder="Tu contrase帽a"

            style={styles.input}

          />

          <button

            type="button"

            onClick={toggleMostrarPassword}

            style={styles.botonToggle}

          >

            {usuario.mostrarPassword ? "馃檲" : "馃憗️"}

          </button>

        </div>

      </div>

      

      {/* Bot贸n de env铆o */}

      <button 

        type="submit"

        style={styles.botonEnviar}

        disabled={!usuario.nombre || !usuario.contrasena}

      >

        Crear cuenta

      </button>

      

      {/* Vista previa */}

      <div style={styles.vistaPrevia}>

        <h4>Vista previa:</h4>

        <p><strong>Nombre:</strong> {usuario.nombre || '(sin nombre)'}</p>

        <p><strong>Contrase帽a:</strong> {usuario.contrasena ? '••••••' : '(sin contrase帽a)'}</p>

      </div>

    </form>

  );

}


// Estilos en objeto JavaScript

const styles = {

  formulario: {

    maxWidth: '400px',

    margin: '0 auto',

    padding: '20px',

    border: '1px solid #ddd',

    borderRadius: '8px',

    backgroundColor: '#f9f9f9'

  },

  grupo: {

    marginBottom: '20px'

  },

  label: {

    display: 'block',

    marginBottom: '5px',

    fontWeight: 'bold'

  },

  input: {

    width: '100%',

    padding: '10px',

    border: '1px solid #ccc',

    borderRadius: '4px',

    fontSize: '16px'

  },

  contador: {

    display: 'block',

    textAlign: 'right',

    color: '#666',

    marginTop: '5px'

  },

  botonToggle: {

    marginLeft: '10px',

    padding: '10px',

    backgroundColor: '#007bff',

    color: 'white',

    border: 'none',

    borderRadius: '4px',

    cursor: 'pointer'

  },

  botonEnviar: {

    width: '100%',

    padding: '12px',

    backgroundColor: '#28a745',

    color: 'white',

    border: 'none',

    borderRadius: '4px',

    fontSize: '16px',

    cursor: 'pointer',

    opacity: 1

  },

  vistaPrevia: {

    marginTop: '20px',

    padding: '15px',

    backgroundColor: '#e9ecef',

    borderRadius: '4px'

  }

};


export default InputAvanzado;

馃摎 Resumen de Conceptos Clave

1. Componente Controlado vs No Controlado

  • Controlado: React maneja el valor (recomendado)

  • jsx

  • <input value={estado} onChange={manejarCambio} />

  • No controlado: El DOM maneja el valor

  • jsx

  • <input defaultValue="valor inicial" />

2. Flujo de Datos

text

Usuario escribe → evento onChange → actualiza estado → se rerenderiza → input muestra nuevo valor

3. Eventos Principales

  • onChange: Cuando el valor cambia

  • onSubmit: Cuando se env铆a el formulario

  • onFocus: Cuando el input recibe foco

  • onBlur: Cuando el input pierde foco

4. Tipos de Input Comunes

jsx

<input type="text" />     // Texto normal

<input type="email" />    // Email

<input type="password" /> // Contrase帽a

<input type="number" />   // N煤meros

<input type="date" />     // Fecha

<textarea />              // Texto multil铆nea

馃殌 Ejemplo Final: Todo en Uno

jsx

import React, { useState } from 'react';


function FormularioTodoUno() {

  const [input, setInput] = useState('');

  

  const manejarCambio = (e) => setInput(e.target.value);

  

  const manejarEnvio = (e) => {

    e.preventDefault();

    alert(`Texto guardado: ${input}`);

    setInput('');

  };

  

  return (

    <div style={{ textAlign: 'center', marginTop: '50px' }}>

      <h1>馃枈️ Formulario Simple en React</h1>

      

      <form onSubmit={manejarEnvio}>

        <input

          type="text"

          value={input}

          onChange={manejarCambio}

          placeholder="Escribe algo incre铆ble..."

          style={{

            padding: '15px',

            fontSize: '18px',

            width: '300px',

            marginBottom: '20px'

          }}

        />

        <br />

        <button

          type="submit"

          style={{

            padding: '15px 30px',

            fontSize: '16px',

            backgroundColor: '#2196F3',

            color: 'white',

            border: 'none',

            borderRadius: '5px',

            cursor: 'pointer'

          }}

        >

          Guardar ✨

        </button>

      </form>

      

      <div style={{ marginTop: '30px' }}>

        <h3>馃幆 Lo que escribes aparece aqu铆:</h3>

        <div style={{

          padding: '20px',

          backgroundColor: '#e3f2fd',

          borderRadius: '5px',

          minHeight: '50px',

          fontSize: '20px',

          fontWeight: 'bold'

        }}>

          {input || '¡Empieza a escribir arriba!'}

        </div>

      </div>

    </div>

  );

}


export default FormularioTodoUno;

✅ Mejores Pr谩cticas

  1. Siempre usar preventDefault() en el submit

  2. Validar datos antes de enviar

  3. Dar feedback visual al usuario

  4. Usar htmlFor y id para accesibilidad

  5. Manejar estados de carga y error

馃帗 Ejercicio para Practicar

Crea un input donde:

  1. Cuente las palabras escritas

  2. Cambie de color cuando tenga m谩s de 10 caracteres

  3. Muestre un mensaje especial cuando diga "React"

¡Ahora tienes las bases para manejar formularios en React!

—------------------------------------

Exactamente, has identificado un patr贸n fundamental en React: levantar el estado (lifting state up). El ejemplo que muestras tiene el estado local dentro del componente FormularioBasico, pero en aplicaciones reales es com煤n mover ese estado al componente padre. Esto permite:

¿Por qu茅 mover el estado al padre?

  1. Compartir datos entre componentes hermanos

  2. Mantener una 煤nica fuente de verdad

  3. Facilitar la comunicaci贸n entre componentes

  4. Centralizar la l贸gica de negocio

Ejemplo con Estado en el Padre

jsx

// Componente PADRE

import React, { useState } from 'react';

import Formulario from './Formulario';

import Mostrador from './Mostrador';


function App() {

  // Estado ahora est谩 en el padre

  const [texto, setTexto] = useState('');

  const [historico, setHistorico] = useState([]);


  // Funci贸n para actualizar el texto

  const manejarCambio = (nuevoTexto) => {

    setTexto(nuevoTexto);

  };


  // Funci贸n para manejar el env铆o

  const manejarEnvio = () => {

    if (texto.trim()) {

      setHistorico([...historico, texto]);

      setTexto('');

    }

  };


  return (

    <div>

      {/* Paso el estado y funciones como props */}

      <Formulario

        texto={texto}

        onCambio={manejarCambio}

        onEnvio={manejarEnvio}

      />

      

      {/* Otro componente que tambi茅n necesita acceso al texto */}

      <Mostrador texto={texto} historico={historico} />

    </div>

  );

}


export default App;

jsx

// Componente HIJO (Formulario.jsx)

import React from 'react';


function Formulario({ texto, onCambio, onEnvio }) {

  const manejarSubmit = (e) => {

    e.preventDefault();

    onEnvio();

  };


  return (

    <form onSubmit={manejarSubmit}>

      <label>

        Escribe algo:

        <input

          type="text"

          value={texto}

          onChange={(e) => onCambio(e.target.value)}

          placeholder="Escribe aqu铆..."

        />

      </label>

      <button type="submit">Enviar</button>

    </form>

  );

}


export default Formulario;

Ventajas de este enfoque:

Ventaja

Descripci贸n

Reutilizaci贸n

El componente formulario puede usarse en m煤ltiples lugares

Separaci贸n de preocupaciones

El formulario solo maneja UI, la l贸gica est谩 en el padre

Testing m谩s f谩cil

Se puede testear la l贸gica y la UI por separado

Escalabilidad

F谩cil agregar validaciones, side effects, etc.

¿Cu谩ndo usar cada enfoque?

Estado local (tu ejemplo):

  • Componentes peque帽os y aislados

  • Formularios independientes

  • Prototipos r谩pidos

  • Estado que no necesita ser compartido

Estado en el padre:

  • Datos que varios componentes necesitan

  • Formularios que afectan otras partes de la UI

  • Aplicaciones con m煤ltiples componentes interconectados

  • Cuando necesitas pasar datos a componentes hermanos

Patr贸n intermedio: Formulario controlado

jsx

// El formulario maneja UI, pero recibe valor y callbacks del padre

function FormularioControllado({ value, onChange, onSubmit }) {

  return (

    <form onSubmit={onSubmit}>

      <input

        type="text"

        value={value}

        onChange={(e) => onChange(e.target.value)}

      />

      <button type="submit">Enviar</button>

    </form>

  );

}

Conclusi贸n: Tu ejemplo es perfecto para entender los conceptos b谩sicos, pero en aplicaciones reales, efectivamente se suele "levantar el estado" al componente padre para mejor arquitectura y mantenibilidad.



Comentarios

Entradas m谩s populares de este blog

18-Ciclo de Vida de un Componente React

20. ¿Que son los Props de React?

17-Componentes en React-estado