Cuando trabajas con formularios en React, los componentes controlados y no controlados definen cómo capturas y manejas la entrada del usuario. Entender esta diferencia te ayuda a decidir cuándo usar estados reactivos y cuándo basta con leer un valor al vuelo, especialmente si trabajas con validaciones o flujos simples de captura.
¿Qué es un componente controlado en React?
Un componente controlado es aquel donde el valor del input vive dentro del estado del componente. Cada tecla que escribe el usuario actualiza ese estado y React vuelve a renderizar la interfaz para reflejarlo.
El patrón parte de un useState importado desde React, que inicializas con un string vacío. Algo así como const [value, setValue] = useState("") [01:09]. Luego conectas el input con dos piezas: el atributo value, que lee del estado, y el evento onChange, que ejecuta setValue(e.target.value) cada vez que el usuario escribe [01:36].
¿Por qué se llama controlado? Porque React controla el valor del input a través del estado. El input no guarda el valor por su cuenta, sino que lo refleja desde tu useState.
Este patrón te da reactividad: cada actualización del estado dispara un nuevo render y la UI muestra siempre el valor más reciente. En el ejemplo de la clase, un input con placeholder Ingresa el código del cupón y un párrafo que muestra en negritas el valor actual demuestran cómo lo escrito aparece de inmediato debajo del campo.
¿Cuándo conviene usar un input controlado?
La ventaja real aparece cuando necesitas validar datos en tiempo real o detectar errores temprano. Como el estado siempre está sincronizado con lo que el usuario escribe, puedes aplicar reglas, deshabilitar botones o mostrar mensajes en cada keystroke.
Algunos casos típicos donde brillan los controlados:
- Formularios con validación inmediata por campo.
- Inputs que dependen entre sí, como filtros o calculadoras.
- Interfaces que muestran previews mientras el usuario escribe.
¿Qué es un componente no controlado en React?
En un componente no controlado, el valor del input vive en el DOM, no en el estado. Tú accedes a ese valor solo cuando lo necesitas, por ejemplo, al hacer clic en un botón.
Para lograrlo se usa el hook useRef, también importado desde React [05:11]. Creas una referencia con const inputRef = useRef<HTMLInputElement>(null) y se la asignas al input mediante el atributo ref={inputRef} [04:55]. El tipado con HTMLInputElement aprovecha TypeScript para tener autocompletado y seguridad sobre las propiedades disponibles.
Luego, una función como handleSubmit lee el valor con inputRef.current.value y lo usa donde haga falta. En el ejemplo del transcript, un carrito de compras con placeholder nombre del producto dispara un alert al pulsar Añadir al carrito, mostrando un mensaje como Nuevo producto en el carrito: pera [05:55].
¿Cuál es la diferencia entre useState y useRef en formularios? useState re-renderiza el componente con cada cambio y mantiene el valor sincronizado. useRef guarda una referencia al elemento del DOM sin provocar renders, ideal para leer el valor solo cuando lo necesitas.
¿Cuándo elegir un input no controlado?
Los no controlados encajan en formularios sencillos donde no necesitas reaccionar a cada cambio, sino capturar el valor final y enviarlo a otro proceso. Al evitar renders por cada tecla, también pueden ser más eficientes en formularios largos.
Ejemplos donde funcionan bien:
- Formularios de envío único sin validación en vivo.
- Integraciones con librerías que manipulan el DOM directamente.
- Captura puntual de un valor para disparar una acción, como agregar un producto al carrito.
¿Cómo decidir entre controlado y no controlado?
La elección depende del caso de uso. Si necesitas mostrar datos al instante, validar mientras el usuario escribe o que la UI reaccione a cada cambio, ve por el patrón controlado con useState. Si tu formulario es simple y solo necesitas leer el valor al final, useRef y el patrón no controlado son suficientes.
Una forma rápida de decidir:
- ¿Necesitas validación en tiempo real? Controlado.
- ¿La UI cambia según lo que escriba el usuario? Controlado.
- ¿Solo capturas el valor al hacer submit o clic? No controlado.
¿Los componentes no controlados son malos? No. Son útiles para formularios simples y para integrar con código no React. Lo importante es saber cuál usar según el contexto.
Ambos patrones conviven sin problema en una misma aplicación. Lo clave es que reconozcas qué te pide cada interfaz: control fino y reactividad, o simplicidad y captura puntual. ¿Tú en qué casos has usado componentes controlados o no controlados? Cuéntanos en los comentarios cómo los aplicarías en tu próximo proyecto.