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
Siempre usar preventDefault() en el submit
Validar datos antes de enviar
Dar feedback visual al usuario
Usar htmlFor y id para accesibilidad
Manejar estados de carga y error
馃帗 Ejercicio para Practicar
Crea un input donde:
Cuente las palabras escritas
Cambie de color cuando tenga m谩s de 10 caracteres
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?
Compartir datos entre componentes hermanos
Mantener una 煤nica fuente de verdad
Facilitar la comunicaci贸n entre componentes
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:
¿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
Publicar un comentario