Español

Desbloquea el poder de la lógica reutilizable en tus aplicaciones React con hooks personalizados. Aprende a crear y aprovechar hooks personalizados para un código más limpio y mantenible.

Hooks Personalizados: Patrones de Lógica Reutilizable en React

Los Hooks de React revolucionaron la forma en que escribimos componentes de React al introducir el estado y las características del ciclo de vida en los componentes funcionales. Entre los muchos beneficios que ofrecen, los hooks personalizados destacan como un mecanismo poderoso para extraer y reutilizar lógica entre múltiples componentes. Esta publicación de blog se sumergirá en el mundo de los hooks personalizados, explorando sus beneficios, creación y uso con ejemplos prácticos.

¿Qué son los Hooks Personalizados?

En esencia, un hook personalizado es una función de JavaScript que comienza con la palabra "use" y puede llamar a otros hooks. Te permiten extraer la lógica del componente en funciones reutilizables. Esta es una forma poderosa de compartir lógica con estado, efectos secundarios u otros comportamientos complejos entre componentes sin recurrir a render props, componentes de orden superior u otros patrones complejos.

Características Clave de los Hooks Personalizados:

Beneficios de Usar Hooks Personalizados

Los hooks personalizados ofrecen varias ventajas significativas en el desarrollo con React:

Creando tu Primer Hook Personalizado

Ilustremos la creación de un hook personalizado con un ejemplo práctico: un hook que rastrea el tamaño de la ventana.

Ejemplo: useWindowSize

Este hook devolverá el ancho y alto actual de la ventana del navegador. También actualizará estos valores cuando se redimensione la ventana.

import { useState, useEffect } from 'react';

function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    window.addEventListener('resize', handleResize);

    // Elimina el event listener en la limpieza
    return () => window.removeEventListener('resize', handleResize);
  }, []); // El array vacío asegura que el efecto solo se ejecute al montar

  return windowSize;
}

export default useWindowSize;

Explicación:

  1. Importar los Hooks Necesarios: Importamos useState y useEffect de React.
  2. Definir el Hook: Creamos una función llamada useWindowSize, adhiriéndonos a la convención de nomenclatura.
  3. Inicializar el Estado: Usamos useState para inicializar el estado windowSize con el ancho y alto iniciales de la ventana.
  4. Configurar el Event Listener: Usamos useEffect para agregar un event listener de 'resize' a la ventana. Cuando se redimensiona la ventana, la función handleResize actualiza el estado windowSize.
  5. Limpieza: Devolvemos una función de limpieza desde useEffect para eliminar el event listener cuando el componente se desmonta. Esto previene fugas de memoria.
  6. Devolver Valores: El hook devuelve el objeto windowSize, que contiene el ancho y alto actuales de la ventana.

Usando el Hook Personalizado en un Componente

Ahora que hemos creado nuestro hook personalizado, veamos cómo usarlo en un componente de React.

import React from 'react';
import useWindowSize from './useWindowSize';

function MyComponent() {
  const { width, height } = useWindowSize();

  return (
    

Ancho de la ventana: {width}px

Alto de la ventana: {height}px

); } export default MyComponent;

Explicación:

  1. Importar el Hook: Importamos el hook personalizado useWindowSize.
  2. Llamar al Hook: Llamamos al hook useWindowSize dentro del componente.
  3. Acceder a los Valores: Desestructuramos el objeto devuelto para obtener los valores de width y height.
  4. Renderizar Valores: Renderizamos los valores de ancho y alto en la interfaz de usuario del componente.

Cualquier componente que use useWindowSize se actualizará automáticamente cuando cambie el tamaño de la ventana.

Ejemplos Más Complejos

Exploremos algunos casos de uso más avanzados para los hooks personalizados.

Ejemplo: useLocalStorage

Este hook te permite almacenar y recuperar datos fácilmente del almacenamiento local (local storage).

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // Estado para almacenar nuestro valor
  // Pasa el valor inicial a useState para que la lógica solo se ejecute una vez
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Obtener del almacenamiento local por clave
      const item = window.localStorage.getItem(key);
      // Parsear el JSON almacenado o, si no hay, devolver initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // Si hay error, también devolver initialValue
      console.log(error);
      return initialValue;
    }
  });

  // Devolver una versión envuelta de la función setter de useState que...
  // ... persiste el nuevo valor en localStorage.
  const setValue = (value) => {
    try {
      // Permitir que el valor sea una función para tener la misma API que useState
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      // Guardar en el almacenamiento local
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
      // Guardar el estado
      setStoredValue(valueToStore);
    } catch (error) {
      // Una implementación más avanzada manejaría el caso de error
      console.log(error);
    }
  };

  useEffect(() => {
    try {
      const item = window.localStorage.getItem(key);
      setStoredValue(item ? JSON.parse(item) : initialValue);
    } catch (error) {
      console.log(error);
    }
  }, [key, initialValue]);

  return [storedValue, setValue];
}

export default useLocalStorage;

Uso:

import React from 'react';
import useLocalStorage from './useLocalStorage';

function MyComponent() {
  const [name, setName] = useLocalStorage('name', 'Invitado');

  return (
    

¡Hola, {name}!

setName(e.target.value)} />
); } export default MyComponent;

Ejemplo: useFetch

Este hook encapsula la lógica para obtener datos de una API.

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`¡Error HTTP! estado: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setLoading(false);
      } catch (error) {
        setError(error);
        setLoading(false);
      }
    }

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

Uso:

import React from 'react';
import useFetch from './useFetch';

function MyComponent() {
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');

  if (loading) return 

Cargando...

; if (error) return

Error: {error.message}

; return (

Título: {data.title}

Completado: {data.completed ? 'Sí' : 'No'}

); } export default MyComponent;

Mejores Prácticas para los Hooks Personalizados

Para asegurar que tus hooks personalizados sean efectivos y mantenibles, sigue estas mejores prácticas:

Errores Comunes a Evitar

Patrones Avanzados

Composición de Hooks Personalizados

Los hooks personalizados pueden componerse entre sí para crear lógica más compleja. Por ejemplo, podrías combinar un hook useLocalStorage con un hook useFetch para persistir automáticamente los datos obtenidos en el almacenamiento local.

Compartir Lógica entre Hooks

Si múltiples hooks personalizados comparten lógica común, puedes extraer esa lógica a una función de utilidad separada y reutilizarla en ambos hooks.

Uso de Contexto con Hooks Personalizados

Los hooks personalizados se pueden usar en conjunto con el Contexto de React para acceder y actualizar el estado global. Esto te permite crear componentes reutilizables que son conscientes y pueden interactuar con el estado global de la aplicación.

Ejemplos del Mundo Real

Aquí hay algunos ejemplos de cómo los hooks personalizados pueden ser usados en aplicaciones del mundo real:

Ejemplo: hook useGeolocation para aplicaciones transculturales como mapas o servicios de entrega

import { useState, useEffect } from 'react';

function useGeolocation() {
  const [location, setLocation] = useState({
    latitude: null,
    longitude: null,
    error: null,
  });

  useEffect(() => {
    if (!navigator.geolocation) {
      setLocation({
        latitude: null,
        longitude: null,
        error: 'La geolocalización no es compatible con este navegador.',
      });
      return;
    }

    const watchId = navigator.geolocation.watchPosition(
      (position) => {
        setLocation({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          error: null,
        });
      },
      (error) => {
        setLocation({
          latitude: null,
          longitude: null,
          error: error.message,
        });
      }
    );

    return () => navigator.geolocation.clearWatch(watchId);
  }, []);

  return location;
}

export default useGeolocation;

Conclusión

Los hooks personalizados son una herramienta poderosa para escribir código de React más limpio, reutilizable y mantenible. Al encapsular lógica compleja en hooks personalizados, puedes simplificar tus componentes, reducir la duplicación de código y mejorar la estructura general de tus aplicaciones. Adopta los hooks personalizados y desbloquea su potencial para construir aplicaciones de React más robustas y escalables.

Comienza identificando áreas en tu código base existente donde la lógica se repite en múltiples componentes. Luego, refactoriza esa lógica en hooks personalizados. Con el tiempo, construirás una biblioteca de hooks reutilizables que acelerará tu proceso de desarrollo y mejorará la calidad de tu código.

Recuerda seguir las mejores prácticas, evitar los errores comunes y explorar patrones avanzados para aprovechar al máximo los hooks personalizados. Con práctica y experiencia, te convertirás en un maestro de los hooks personalizados y en un desarrollador de React más eficaz.

Hooks Personalizados: Patrones de Lógica Reutilizable en React | MLOG