← Volver al Blog

React Hooks Explicados: useState y useEffect para Principiantes

Guía completa de React Hooks para principiantes. Aprende useState y useEffect con ejemplos prácticos, casos de uso y mejores prácticas.

Big JSON Team10 min de lecturabeginner
B

Big JSON Team

Technical Writer

Expert in JSON data manipulation, API development, and web technologies. Passionate about creating tools that make developers' lives easier.

10 min lectura

# React Hooks Explicados: useState y useEffect para Principiantes

Los Hooks revolucionaron React en 2019, permitiendo usar estado y efectos en componentes funcionales. Esta guía explica los 2 Hooks más importantes: useState y useEffect.

---

¿Qué Son los Hooks?

Hooks son funciones especiales que te permiten "enganchar" características de React en componentes funcionales.

Antes de Hooks (Clases)

class Contador extends React.Component {

constructor(props) {

super(props);

this.state = { count: 0 };

}

render() {

return (

<button onClick={() => this.setState({ count: this.state.count + 1 })}>

Clicks: {this.state.count}

</button>

);

}

}

Con Hooks (Funciones)

function Contador() {

const [count, setCount] = useState(0);

return (

<button onClick={() => setCount(count + 1)}>

Clicks: {count}

</button>

);

}

Mucho más simple!

---

Hook #1: useState

useState te permite añadir estado a componentes funcionales.

Sintaxis Básica

const [variable, setVariable] = useState(valorInicial);
  • variable: El valor actual del estado
  • setVariable: Función para actualizar el estado
  • valorInicial: Valor al montar el componente

Ejemplo Simple

import { useState } from 'react';

function ContadorSimple() {

const [count, setCount] = useState(0);

return (

<div>

<p>Has hecho clic {count} veces</p>

<button onClick={() => setCount(count + 1)}>

Incrementar

</button>

</div>

);

}

Tipos de Datos en useState

String

const [nombre, setNombre] = useState('');

<input

value={nombre}

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

/>

Boolean

const [mostrar, setMostrar] = useState(false);

<button onClick={() => setMostrar(!mostrar)}>

Toggle

</button>

{mostrar && <p>Contenido visible</p>}

Array

const [items, setItems] = useState([]);

const agregarItem = () => {

setItems([...items, 'Nuevo item']);

};

Object

const [usuario, setUsuario] = useState({

nombre: '',

email: ''

});

const actualizar = () => {

setUsuario({ ...usuario, nombre: 'Ana' });

};

Múltiples Estados

function Formulario() {

const [nombre, setNombre] = useState('');

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

const [edad, setEdad] = useState(0);

return (

<form>

<input

value={nombre}

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

/>

<input

value={email}

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

/>

<input

type="number"

value={edad}

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

/>

</form>

);

}

Actualizar Estado Basado en Anterior

Incorrecto:

setCount(count + 1);

setCount(count + 1); // No funciona como esperas

Correcto:

setCount(prevCount => prevCount + 1);

setCount(prevCount => prevCount + 1); // Funciona bien

---

Hook #2: useEffect

useEffect te permite realizar efectos secundarios en componentes.

¿Qué Son Efectos Secundarios?

  • Fetch de datos (API calls)
  • Suscripciones
  • Manipular DOM directamente
  • Timers (setTimeout, setInterval)
  • Logging

Sintaxis Básica

useEffect(() => {

// Código del efecto

return () => {

// Cleanup (opcional)

};

}, [dependencias]);

Ejemplo: Actualizar Título

import { useState, useEffect } from 'react';

function Contador() {

const [count, setCount] = useState(0);

useEffect(() => {

document.title = Clicks: ${count};

}, [count]); // Se ejecuta cuando count cambia

return (

<button onClick={() => setCount(count + 1)}>

Clicks: {count}

</button>

);

}

Array de Dependencias

Sin dependencias - Cada render

useEffect(() => {

console.log('Se ejecuta en CADA render');

});

Array vacío - Solo al montar

useEffect(() => {

console.log('Solo al montar el componente');

}, []); // ← Array vacío

Con dependencias - Cuando cambian

useEffect(() => {

console.log('count cambió');

}, [count]); // Se ejecuta cuando count cambia

---

Casos de Uso Comunes

1. Fetch de API

function Usuarios() {

const [usuarios, setUsuarios] = useState([]);

const [loading, setLoading] = useState(true);

useEffect(() => {

fetch('https://api.example.com/usuarios')

.then(res => res.json())

.then(data => {

setUsuarios(data);

setLoading(false);

});

}, []); // Solo al montar

if (loading) return <p>Cargando...</p>;

return (

<ul>

{usuarios.map(user => (

<li key={user.id}>{user.nombre}</li>

))}

</ul>

);

}

2. Temporizador

function Reloj() {

const [segundos, setSegundos] = useState(0);

useEffect(() => {

const interval = setInterval(() => {

setSegundos(s => s + 1);

}, 1000);

// Cleanup: limpiar al desmontar

return () => clearInterval(interval);

}, []);

return <p>Segundos: {segundos}</p>;

}

3. Event Listeners

function TamanoPantalla() {

const [ancho, setAncho] = useState(window.innerWidth);

useEffect(() => {

const handleResize = () => {

setAncho(window.innerWidth);

};

window.addEventListener('resize', handleResize);

// Cleanup

return () => {

window.removeEventListener('resize', handleResize);

};

}, []);

return <p>Ancho: {ancho}px</p>;

}

4. LocalStorage

function ContadorPersistente() {

const [count, setCount] = useState(() => {

const guardado = localStorage.getItem('count');

return guardado ? parseInt(guardado) : 0;

});

useEffect(() => {

localStorage.setItem('count', count);

}, [count]);

return (

<button onClick={() => setCount(count + 1)}>

Clicks: {count}

</button>

);

}

---

Proyecto Completo: Lista de Tareas

import { useState, useEffect } from 'react';

function ListaTareas() {

const [tareas, setTareas] = useState(() => {

const guardadas = localStorage.getItem('tareas');

return guardadas ? JSON.parse(guardadas) : [];

});

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

// Guardar en localStorage cuando cambian las tareas

useEffect(() => {

localStorage.setItem('tareas', JSON.stringify(tareas));

}, [tareas]);

const agregarTarea = () => {

if (input.trim()) {

setTareas([...tareas, {

id: Date.now(),

texto: input,

completada: false

}]);

setInput('');

}

};

const toggleTarea = (id) => {

setTareas(tareas.map(tarea =>

tarea.id === id

? { ...tarea, completada: !tarea.completada }

: tarea

));

};

const eliminarTarea = (id) => {

setTareas(tareas.filter(tarea => tarea.id !== id));

};

return (

<div>

<h1>Mis Tareas</h1>

<div>

<input

value={input}

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

onKeyPress={(e) => e.key === 'Enter' && agregarTarea()}

placeholder="Nueva tarea..."

/>

<button onClick={agregarTarea}>Agregar</button>

</div>

<ul>

{tareas.map(tarea => (

<li key={tarea.id}>

<input

type="checkbox"

checked={tarea.completada}

onChange={() => toggleTarea(tarea.id)}

/>

<span style={{

textDecoration: tarea.completada ? 'line-through' : 'none'

}}>

{tarea.texto}

</span>

<button onClick={() => eliminarTarea(tarea.id)}>

Eliminar

</button>

</li>

))}

</ul>

<p>Total: {tareas.length} | Completadas: {tareas.filter(t => t.completada).length}</p>

</div>

);

}

---

Errores Comunes

1. Olvidar Dependencias

Problema:

useEffect(() => {

console.log(count);

}, []); // count no está en dependencias

Solución:

useEffect(() => {

console.log(count);

}, [count]);

2. Loops Infinitos

Problema:

useEffect(() => {

setCount(count + 1); // ¡Causa loop infinito!

}, [count]);

Solución:

// Usa condición o quita dependencia

useEffect(() => {

if (count < 10) {

setCount(count + 1);

}

}, [count]);

3. No Limpiar Efectos

Problema:

useEffect(() => {

const timer = setInterval(() => {...}, 1000);

// No limpia el timer

});

Solución:

useEffect(() => {

const timer = setInterval(() => {...}, 1000);

return () => clearInterval(timer); // Cleanup

}, []);

---

Reglas de los Hooks

✅ DO's

  • Llama Hooks al nivel superior - No dentro de loops/condiciones
  • Usa en componentes funcionales - O custom hooks
  • Nombres de custom hooks: Empiezan con "use"
  • ❌ DON'Ts

    No hagas esto:

    if (condicion) {
    

    const [count, setCount] = useState(0); // ❌ Error

    }

    Haz esto:

    const [count, setCount] = useState(0);
    

    if (condicion) {

    // Usa count aquí

    }

    ---

    Custom Hooks

    Crea tus propios Hooks reutilizables:

    // Hook personalizado
    

    function useFetch(url) {

    const [data, setData] = useState(null);

    const [loading, setLoading] = useState(true);

    useEffect(() => {

    fetch(url)

    .then(res => res.json())

    .then(data => {

    setData(data);

    setLoading(false);

    });

    }, [url]);

    return { data, loading };

    }

    // Usar el hook

    function App() {

    const { data, loading } = useFetch('https://api.example.com/data');

    if (loading) return <p>Cargando...</p>;

    return <div>{JSON.stringify(data)}</div>;

    }

    ---

    Otros Hooks Útiles

    useContext

    const valor = useContext(MiContexto);

    useRef

    const inputRef = useRef(null);
    
    

    <input ref={inputRef} />

    <button onClick={() => inputRef.current.focus()}>

    Focus Input

    </button>

    useMemo

    const resultado = useMemo(() =>{
    

    return calcularValorCostoso(dep);

    }, [dep]);

    ---

    Conclusión

    Los Hooks useState y useEffect son fundamentales en React moderno:

    useState - Gestiona estado del componente

    useEffect - Maneja efectos secundarios

    ✅ Más simples que componentes de clase

    ✅ Reutilizables con custom hooks

    Próximo paso: Practica creando una app de tareas con estos Hooks.

    ---

    Recursos Relacionados

    ---

    Última actualización: 15 de febrero de 2026
    Share:

    Artículos Relacionados

    Read in English