Controlled fields, useEffect
2026-02-27
Contenido
useEffectHasta ahora se ha trabajado con eventos capturando acciones del usuario.
Sin embargo, al trabajar con formularios surge una cuestión fundamental:
¿Quién controla el valor del input?
¿El DOM o React?
Recordemos que en HTML puro o, el valor de un <input> está gestionado directamente por el DOM.
En React, podemos hacer que el valor del input esté controlado por el estado del componente.
A esto lo llamamos controlled input.
Un controlled input es un elemento de formulario cuyo valor:
onChange)Única fuente de verdad (single source of truth).
import { useState } from "react";
function FormularioNombre() {
const [nombre, setNombre] = useState("");
function manejarCambio(event) {
setNombre(event.target.value);
}
return (
<div>
<input type="text"
value={nombre}
onChange={manejarCambio}
/>
<p>El nombre introducido es: {nombre}</p>
</div>
);
}El valor del input se sincroniza con el estado
Cada vez que el estado cambia: El componente se vuelve a ejecutar El JSX se vuelve a generar El valor del input se sincroniza con el estado
import { useState } from "react";
function FormularioSimple() {
const [email, setEmail] = useState("");
function handleChange(event) {
setEmail(event.target.value);
}
function handleSubmit(event) {
event.preventDefault(); // Evita la recarga del navegador
console.log("Formulario enviado");
console.log("Email:", email);
setEmail(""); // Limpieza opcional del campo
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={handleChange}
/>
<button type="submit">Enviar</button>
</form>
);
}Referencia: https://es.react.dev/reference/react-dom/components/input#controlling-an-input-with-a-state-variable
life-cycleuse____useEffectuseEffect es un Hook que permite ejecutar efectos secundarios dentro de un componente funcional.useEffectComportamiento:
Interpretación conceptual:
El efecto acompaña siempre al render.
Comportamiento:
Uso habitual:
Interpretación conceptual:
El efecto ocurre una única vez al crear el componente.
Comportamiento:
Interpretación conceptual:
El efecto depende del estado indicado.
React compara el valor anterior con el nuevo y decide si debe ejecutar el efecto.
fetch()Hasta ahora nuestros componentes eran completamente locales.
Sin embargo, en aplicaciones reales necesitamos:
Para ello utilizamos fetch().
fetchUtiliza las Promises
Interpretación simple:
fetch() dentro de useEffectEn React, lo habitual es realizar la descarga cuando el componente se monta.
Para ello:
useEffect[]import { useState, useEffect } from "react";
function Pokemon() {
const [pokemon, setPokemon] = useState(null);
useEffect(() => {
fetch("https://pokeapi.co/api/v2/pokemon/1")
.then(response => response.json())
.then(data => setPokemon(data));
}, []);
if (!pokemon) return <p>Cargando...</p>;
return (
<div>
<h2>{pokemon.name}</h2>
<img
src={pokemon.sprites.front_default}
alt={pokemon.name}
/>
</div>
);
}useEffectSi eliminamos el array vacío:
El efecto se ejecutará en cada render.
Como actualizar estado provoca render, se generará un bucle infinito.
useEffect conecta React con el exterior.
fetch() permite traer datos del exterior.
El estado vuelve a controlar el render.
En la siguiente sección formalizaremos esto utilizando async / await.
async y awaitHasta ahora hemos utilizado fetch() con encadenamiento.
Existe una forma más clara y estructurada de escribir código asíncrono:
asyncawaitSu objetivo es hacer que el código sea más legible.
async?await?asyncfetchInterpretación conceptual:
El código se lee de arriba hacia abajo.
async / await dentro de useEffectEn React, lo habitual es declarar una función interna y ejecutarla.
import { useState, useEffect } from "react";
function Pokemon() {
const [pokemon, setPokemon] = useState(null);
useEffect(() => {
async function fetchData() {
const response = await fetch(
"https://pokeapi.co/api/v2/pokemon/1"
);
const data = await response.json();
setPokemon(data);
}
fetchData();
}, []);
if (!pokemon) return <p>Cargando...</p>;
return (
<div>
<h2>{pokemon.name}</h2>
<img
src={pokemon.sprites.front_default}
alt={pokemon.name}
/>
</div>
);
}Porque useEffect no debe recibir una función asíncrona directamente.
Por eso declaramos la función dentro y luego la ejecutamos.
async / awaituseEffectawait espera la respuestaasync / await no cambia lo que hace el programa.
Solo cambia la forma de escribirlo:
Más claro.
Más estructurado.
Más fácil de mantener.