React

React

Tutorial React: Estado local con useState y useReducer

React: Aprende a gestionar el estado local con useState y useReducer en este tutorial práctico. Mejora tus habilidades en componentes funcionales con React.

¿Qué es el estado local?

El estado local en React se refiere a los datos que son manejados dentro de un componente y que afectan su comportamiento y renderizado. Este estado es privado al componente en el que se define, lo que significa que no es accesible directamente desde otros componentes. En React, el estado local se gestiona principalmente mediante los hooks useState y useReducer.

El estado local permite a los componentes de React mantener y actualizar datos sin necesidad de recurrir a un sistema de gestión de estado global. Esto es útil para componentes que manejan datos específicos y no necesitan compartir esa información con otros componentes.

Consideraciones sobre el estado local

El estado local es fundamental para crear componentes interactivos en React. Sin embargo, es importante tener en cuenta las siguientes consideraciones:

  • Encapsulamiento: El estado local está encapsulado dentro del componente, lo que mejora la modularidad y la reutilización del código.
  • Renderización: Cada vez que se actualiza el estado local, el componente se vuelve a renderizar, lo que puede afectar el rendimiento si no se maneja adecuadamente.
  • Simplicidad: Para estados simples y componentes individuales, useState es generalmente suficiente. Para estados más complejos o cuando las actualizaciones dependen del estado anterior, useReducer puede ser más apropiado.

¿Qué es useState?

useState es un hook en React que permite añadir estado local a los componentes funcionales. Antes de la introducción de los hooks, el estado solo podía ser manejado en componentes de clase mediante el uso de this.state y this.setState. Con useState, se puede manejar el estado en componentes funcionales de manera más sencilla y declarativa.

El uso de useState implica la declaración de una variable de estado y una función para actualizar esa variable. Esta declaración se realiza mediante la desestructuración de un array devuelto por useState. La sintaxis básica de useState es la siguiente:

const [estado, setEstado] = useState(valorInicial);
  • estado: representa el valor actual del estado.
  • setEstado: es una función que se utiliza para actualizar el valor del estado.
  • valorInicial: es el valor inicial del estado.

Ejemplo básico

A continuación se muestra un ejemplo básico de cómo utilizar useState para manejar el estado de un contador en un componente funcional:

// Contador.jsx
import { useState } from 'react';

export default function Contador() {
  const [contador, setContador] = useState(0);

  const incrementar = () => {
    setContador(contador + 1);
  };

  return (
    <div>
      <p>Contador: {contador}</p>
      <button onClick={incrementar}>Incrementar</button>
    </div>
  );
}

En este ejemplo, useState inicializa el estado contador a 0. La función incrementar actualiza el estado utilizando setContador. Cada vez que se hace clic en el botón, setContador incrementa el valor del contador y React vuelve a renderizar el componente con el nuevo estado.

Ejemplo con estado complejo

En situaciones donde el estado es más complejo, como un objeto, useState también puede ser utilizado. Es importante tener en cuenta que, al actualizar el estado que es un objeto, se debe copiar el estado anterior y luego modificar las propiedades necesarias. Esto se puede hacer utilizando el spread operator(...) o Object.assign.

// PerfilUsuario.jsx
import { useState } from 'react';

export default function PerfilUsuario() {
  const [usuario, setUsuario] = useState({
    nombre: 'Juan',
    edad: 30,
    direccion: 'Calle Falsa 123'
  });

  const actualizarEdad = () => {
    setUsuario(prevUsuario => ({
      ...prevUsuario,
      edad: prevUsuario.edad + 1
    }));
  };

  return (
    <div>
      <p>Nombre: {usuario.nombre}</p>
      <p>Edad: {usuario.edad}</p>
      <p>Dirección: {usuario.direccion}</p>
      <button onClick={actualizarEdad}>Cumplir años</button>
    </div>
  );
}

En este ejemplo, useState se utiliza para manejar el estado de un objeto usuario. La función actualizarEdad usa el valor previo del estado (prevUsuario) y el spread operator(...) para actualizar únicamente la propiedad edad.

Consideraciones importantes

  • Inicialización del estado: El valor inicial del estado solo se establece la primera vez que el componente se renderiza. Si el valor inicial depende de cálculos costosos, se puede pasar una función a useState para que se ejecute solo una vez.
const [valor, setValor] = useState(() => calcularValorInicial());
  • Inmutabilidad: Es crucial no mutar directamente el estado anterior. En su lugar, se debe crear una nueva copia del estado con los cambios necesarios.
setUsuario(prevUsuario => ({
  ...prevUsuario,
  nuevaPropiedad: nuevoValor
}));
  • Renderización: Cada vez que se actualiza el estado usando setEstado, el componente se vuelve a renderizar. Esto puede afectar el rendimiento si no se maneja adecuadamente.

¿Qué es useReducer?

useReducer es un hook en React que se utiliza para manejar el estado de los componentes funcionales, proporcionando una alternativa a useState cuando se necesita manejar estados más complejos o con múltiples transiciones. Este hook es especialmente útil cuando las actualizaciones del estado dependen del estado anterior o cuando se requiere una lógica de actualización más sofisticada.

El uso de useReducer implica tres elementos clave:

  1. Estado inicial: El estado con el que el hook comenzará a trabajar.
  2. Reducer: Una función que define cómo se debe actualizar el estado en respuesta a diferentes acciones.
  3. Dispatch: Una función que se utiliza para enviar acciones al reducer.

Sintaxis básica

La sintaxis básica de useReducer es la siguiente:

const [state, dispatch] = useReducer(reducer, initialState);
  • state: Representa el estado actual.
  • dispatch: Es una función que se utiliza para enviar acciones al reducer.
  • reducer: Es una función que toma el estado actual y una acción, y devuelve un nuevo estado.
  • initialState: Es el estado inicial del componente.

Ejemplo básico

A continuación se muestra un ejemplo básico de cómo utilizar useReducer para manejar el estado de un contador:

// ContadorConReducer.jsx
import { useReducer } from 'react';

const initialState = { contador: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'incrementar':
      return { contador: state.contador + 1 };
    case 'decrementar':
      return { contador: state.contador - 1 };
    default:
      throw new Error('Acción no soportada');
  }
}

export default function ContadorConReducer() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Contador: {state.contador}</p>
      <button onClick={() => dispatch({ type: 'incrementar' })}>Incrementar</button>
      <button onClick={() => dispatch({ type: 'decrementar' })}>Decrementar</button>
    </div>
  );
}

En este ejemplo, useReducer se utiliza para manejar el estado del contador. El estado inicial es { contador: 0 } y la función reducer define cómo actualizar el estado en función de las acciones incrementar y decrementar. El dispatch se utiliza para enviar las acciones correspondientes.

Cuando usar useReducer

useReducer es más adecuado en las siguientes situaciones:

  • Estados complejos: Cuando el estado es un objeto o un array con múltiples propiedades que necesitan ser actualizadas de manera coherente.
  • Lógica de actualización compleja: Cuando las actualizaciones del estado dependen del estado anterior o requieren múltiples pasos.
  • Escalabilidad: Cuando se espera que la lógica de actualización del estado crezca y se vuelva más compleja con el tiempo.

Ejemplo avanzado

Ejemplo más avanzado de useReducer para manejar el estado de una lista de tareas:

// ListaDeTareas.jsx
import { useReducer } from 'react';

const initialState = { tareas: [] };

function reducer(state, action) {
  switch (action.type) {
    case 'agregar':
      return { tareas: [...state.tareas, action.payload] };
    case 'eliminar':
      return { tareas: state.tareas.filter(tarea => tarea.id !== action.payload.id) };
    case 'completar':
      return {
        tareas: state.tareas.map(tarea =>
          tarea.id === action.payload.id ? { ...tarea, completada: !tarea.completada } : tarea
        )
      };
    default:
      throw new Error('Acción no soportada');
  }
}

export default function ListaDeTareas() {
  const [state, dispatch] = useReducer(reducer, initialState);

  const agregarTarea = tarea => {
    dispatch({ type: 'agregar', payload: tarea });
  };

  const eliminarTarea = id => {
    dispatch({ type: 'eliminar', payload: { id } });
  };

  const completarTarea = id => {
    dispatch({ type: 'completar', payload: { id } });
  };

  return (
    <div>
      <button onClick={() => agregarTarea({ id: Date.now(), texto: 'Nueva tarea', completada: false })}>
        Agregar Tarea
      </button>
      <ul>
        {state.tareas.map(tarea => (
          <li key={tarea.id}>
            <span style={{ textDecoration: tarea.completada ? 'line-through' : 'none' }}>
              {tarea.texto}
            </span>
            <button onClick={() => completarTarea(tarea.id)}>
              {tarea.completada ? 'Descompletar' : 'Completar'}
            </button>
            <button onClick={() => eliminarTarea(tarea.id)}>Eliminar</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

En este ejemplo, useReducer se utiliza para manejar una lista de tareas con acciones para agregar, eliminar y completar tareas. Este enfoque permite una gestión del estado más estructurada y escalable, adecuada para aplicaciones más complejas.

Cuando usar useState vs cuando usar useReducer

useState y useReducer son dos hooks en React que permiten manejar el estado local de un componente funcional. Sin embargo, cada uno tiene su propio conjunto de casos de uso y es importante saber cuándo utilizar uno sobre el otro.

Cuándo usar useState

useState es ideal para manejar estados simples y es la elección más común cuando se cumplen las siguientes condiciones:

  • Estado simple: Si el estado es un valor primitivo (como un número, string o booleano) o un objeto con pocas propiedades, useState es más que suficiente.
  • Actualizaciones independientes: Cuando las actualizaciones del estado no dependen del estado anterior, useState resulta más sencillo y directo.
  • Componentes individuales: Para componentes que no requieren una lógica de estado compleja y que son relativamente autónomos.

Cuándo usar useReducer

useReducer es más adecuado para manejar estados complejos y lógicas de actualización sofisticadas. Se recomienda su uso en las siguientes situaciones:

  • Estado complejo: Cuando el estado es un objeto o array con múltiples propiedades o elementos que necesitan ser actualizados de manera coherente.
  • Lógica de actualización compleja: Cuando las actualizaciones del estado dependen del estado anterior o requieren una lógica de actualización más estructurada.
  • Escalabilidad: Cuando se espera que la lógica de actualización del estado crezca y se vuelva más compleja con el tiempo.
  • Mejor legibilidad: En situaciones donde la lógica de actualización del estado puede resultar en múltiples llamadas a setState, useReducer puede mejorar la legibilidad y mantenibilidad del código.

Resumen de criterios de elección

  • Utiliza useState para estados simples y cuando las actualizaciones no dependen del estado anterior.
  • Utiliza useReducer para estados complejos y cuando las actualizaciones del estado dependen del estado anterior o requieren una lógica de actualización más sofisticada.
Certifícate en React con CertiDevs PLUS

Ejercicios de esta lección Estado local con useState y useReducer

Evalúa tus conocimientos de esta lección Estado local con useState y useReducer con nuestros retos de programación de tipo Test, Puzzle, Código y Proyecto con VSCode, guiados por IA.

Todas las lecciones de React

Accede a todas las lecciones de React y aprende con ejemplos prácticos de código y ejercicios de programación con IDE web sin instalar nada.

Introducción A React Y Su Ecosistema

React

Introducción Y Entorno

Instalar React Y Crear Nuevo Proyecto

React

Introducción Y Entorno

Introducción A Jsx

React

Componentes

Introducción A Componentes

React

Componentes

Componentes Funcionales

React

Componentes

Eventos En React

React

Componentes

Props Y Manejo De Datos Entre Componentes

React

Componentes

Renderizado Condicional

React

Componentes

Renderizado Iterativo Con Bucles

React

Componentes

Manejo De Clases Y Estilos

React

Componentes

Introducción A Los Hooks

React

Hooks

Estado Y Ciclo De Vida De Los Componentes

React

Hooks

Hooks Para Manejo De Estado Y Efectos Secundarios

React

Hooks

Hooks Para Gestión De Estado Complejo Y Contexto

React

Hooks

Hooks Para Optimización Y Actualizaciones Concurrentes

React

Hooks

Introducción A React Router

React

Navegación Y Enrutamiento

Definición Y Manejo De Rutas

React

Navegación Y Enrutamiento

Rutas Anidadas Y Rutas Dinámicas

React

Navegación Y Enrutamiento

Navegación Programática Y Redireccionamiento

React

Navegación Y Enrutamiento

Nuevos Métodos Create De React Router

React

Navegación Y Enrutamiento

Solicitudes Http Con Fetch Api

React

Interacción Http Con Backend

Solicitudes Http Con Axios

React

Interacción Http Con Backend

Estado Local Con Usestate Y Usereducer

React

Servicios Y Gestión De Estado

Estado Global Con Context Api

React

Servicios Y Gestión De Estado

Estado Global Con Redux Toolkit

React

Servicios Y Gestión De Estado

Custom Hooks Para Servicios Compartidos

React

Servicios Y Gestión De Estado

Certificados de superación de React

Supera todos los ejercicios de programación del curso de React y obtén certificados de superación para mejorar tu currículum y tu empleabilidad.

En esta lección

Objetivos de aprendizaje de esta lección

  • Comprender el concepto de estado local en React.
  • Aprender a utilizar useState para manejar estados simples en componentes.
  • Conocer el uso de useReducer para gestionar estados más complejos.
  • Diferenciar cuándo usar useState y useReducer según el caso de uso.
  • Implementar actualizaciones de estado considerando la inmutabilidad y rendimiento.
  • Aplicar técnicas avanzadas de gestión de estado en componentes funcionales.