Comprende, con ejemplos claros, cómo funcionan los componentes controlados y no controlados en React para manejar formularios. Verás cómo usar useState, useRef, el evento onChange y la reactividad para capturar y mostrar datos del usuario con precisión.
¿Qué son componentes controlados y no controlados?
Un componente controlado mantiene el valor del input en un estado local y actualiza la UI de forma reactiva con cada cambio del usuario. Esto da más control, facilita la validación y permite detectar errores antes.
En cambio, un componente no controlado no sincroniza el valor del input con el estado en cada pulsación. En su lugar, utiliza una referencia con useRef para leer el valor del DOM en un momento específico, por ejemplo, al hacer clic en un botón.
Controlado: el input usa value + onChange para actualizar el estado en tiempo real.
No controlado: el input usa ref para leer su valor solo cuando se necesita.
Beneficio del controlado: mayor control, validaciones tempranas y UI siempre alineada con el estado.
Beneficio del no controlado: simplicidad en casos puntuales donde solo lees el valor al final.
¿Cómo crear un componente controlado en React?
Aquí el valor del input vive en el estado. Cada vez que escribes, onChange ejecuta setValue(e.target.value) y la interfaz se vuelve a renderizar para mostrar el texto actualizado.
importReact,{ useState }from'react';exportfunctionControlledComponent(){const[value, setValue]=useState('');return(<><inputtype="text"placeholder="Ingresa el código del cupón (ej: 10 % off)"value={value}onChange={(e)=>setValue(e.target.value)}/><p> cupón de descuento: <b>{value}</b></p></>);}
Claves del patrón:
useState: crea y guarda el valor del input.
onChange: toma e.target.value en cada tecla.
Reactividad: al cambiar el estado, React vuelve a renderizar y la UI refleja el valor actual.
Validación temprana: al tener el valor en estado, puedes validar mientras el usuario escribe.
¿Cómo implementar un componente no controlado con useRef?
En este patrón, el valor del input no se guarda en estado. Se lee bajo demanda usando useRef. Útil cuando solo necesitas el dato al enviar.
importReact,{ useRef }from'react';exportfunctionUncontrolledComponent(){const inputRef =useRef<HTMLInputElement>(null);consthandleSubmit=()=>{if(inputRef.current){alert(`Nuevo producto en el carrito: ${inputRef.current.value} 🛒✨`);}};return(<><inputtype="text"placeholder="nombre del producto (ej: manzana)"ref={inputRef}/><buttononClick={handleSubmit}>añadir al carrito</button></>);}
¿Cuándo elegir controlado o no controlado?
Usa controlado si necesitas validaciones en vivo y errores tempranos.
Usa no controlado si el formulario es simple y solo lees el valor al final.
Recuerda: controlado = mayor control; no controlado = menor complejidad.
¿Qué habilidades prácticas refuerzas?
Manejo de estado con useState y patrón de componente controlado.
Lectura del DOM con useRef y patrón no controlado.
Manejo de eventos con onChange y funciones como handleSubmit.
Buenas prácticas de contenido: placeholder claro y ejemplos de entrada.
¿Qué keywords y datos importan?
componentes controlados, componentes no controlados, formularios, inputs, useState, useRef, onChange, estado local, reactividad, renderizado, validación, TypeScript, ref, DOM, alert.
¿Te ha servido este tema o ya tuviste que elegir entre ambos patrones? Cuéntanos en los comentarios cómo lo aplicaste y qué dudas te quedaron.
A lo que entiendo y según mi experiencia, siempre me ha parecido necesario el uso de componentes controlados en formularios, pues un 95% de los casos necesito hacer validaciones de algún tipo desde frontend y tiene mucho sentido hacerlo aprovechando la reactividad de la librería.
Pero, super valioso saber a nivel conceptual qué representan ambos tipos de componente. ☺️
Por lo que entendi:
Los componentes controlados son aquellos donde react maneja el estado
Los componentes no controlados son aquellos donde react puede acceder al valor, pero no lo maneja.
Una practica un poco mas comun cuando tratamos con componentes no controlados, es usar un elemento form y pasar a este la funcion de handleSubmit (semanticamente mas correcto tambien) y en esta funcion utilizar el api de FormData para obtener los valores.
Importante: Los cambos dentro de el form deben de ser nombrados para que esto funcione correctamente
Como una muestra, asi quedaria el handleSubmit:
 consthandleSubmit=(e:FormEvent)=>{  e.preventDefault(); const data =newFormData(e.targetasHTMLFormElement); const productName = data.get("product"); alert(`New product added: ${productName}!`); };
Cuándo preferir componentes no controlados (uncontrolled)
🚀 Performance en formularios grandes
Cuando tienes muchos inputs (decenas o cientos), los controlados disparan re-render en cada pulsación.
Los no controlados mantienen el estado en el DOM y React no se involucra hasta que tú quieras (ej. al enviar el formulario).
🔥 Mejora de rendimiento.
Componentes con estado interno natural (como<input type="file">)
Inputs como archivos, checkboxes personalizados o elementos de formularios nativos no se controlan bien con React.
El input file no se puede controlar vía value.
"Para formularios simples o cuando necesitas validación instantánea y deshabilitar el botón de Submit si hay errores, usa Controlados."
"Pero si tu formulario es masivo (50+ campos) o no necesitas feedback en tiempo real, usa No Controlados para respetar la naturaleza (rendimiento) del navegador."
el no controlado puede ser util para un input sencillo de un search donde no sean necesarias validaciones complejas y seria mucho mas eficiente ya que no causa un re-render
Añadí una pequeña validación con el operador ternario para saber si el usuario agregó o no un producto al carrito.
consthandleSubmit=()=>{ inputRef.current?.value ===''?alert(`No agregaste productos, por favor agrege un producto para continuar`):alert(`nuevo producto: ${inputRef.current?.value}`)}```const handleSubmit = () => { inputRef.current?.value === '' ? alert(`No agregaste productos, por favor agrege un producto para continuar`) : alert(`nuevo producto: ${inputRef.current?.value}` )}