Optimización de Debounce y Throttle en React con LowDash

Clase 4 de 10Curso de Next.js: Optimización y Manejo de Grandes Datasets

Resumen

¿Cómo implementar debouncing y throttling con Lodash en React?

Cuando trabajamos con React, es común usar librerías auxiliares que nos faciliten el control de ciertas funcionalidades. Una de las más populares es Lodash, conocida por su capacidad de manipulación de datos. Sin embargo, cuando se trata de implementar técnicas como el debouncing y throttling, debemos ser cuidadosos para asegurar que funcionen adecuadamente. Veamos cómo lograrlo.

¿Qué son el debouncing y throttling?

Ambas técnicas están relacionadas con el manejo de la ejecución de funciones en el tiempo:

  • Debouncing: asegura que una función solo se ejecuta después de que haya dejado de ser llamada durante un periodo de tiempo determinado. Ideal para manejar eventos de entrada del usuario, donde queremos evitar múltiples llamadas simultáneas.

  • Throttling: limita la cantidad de veces que se ejecuta una función en un periodo de tiempo, sin importar cuántas veces el evento es llamado.

¿Cuál es el problema al usar Lodash en React?

Al implementar estas técnicas en un proyecto de React con Lodash, podemos encontrarnos con un problema: las funciones que dependen del tiempo (como debounce y throttle) deben garantizar que no se crean múltiples instancias cada vez que nuestro componente se renderiza. React, al re-renderizar componentes por cambios de estado, recrea estas funciones de manera indeseada, lo cual ocasiona que el efecto deseado no funcione correctamente.

¿Cómo puedo resolverlo usando useCallback?

Para corregir este problema, React nos proporciona dos hooks útiles: useRef y useCallback. En este caso, usaremos useCallback para asegurarnos que la función debounce se instancie solo una vez durante el ciclo de vida del componente.

import { useCallback } from 'react';
import debounce from 'lodash/debounce';

const DebouncedComponent = () => {
  const debouncedSearch = useCallback(
    debounce((searchTerm) => {
      // Aquí iría la lógica de la búsqueda
      console.log('Searching:', searchTerm);
    }, 300), // Tiempo de espera en milisegundos
    [] // Array de dependencias vacío para asegurar un solo llamado
  );

  return (
    <input
      type="text"
      onChange={(e) => debouncedSearch(e.target.value)}
    />
  );
}

¿Qué ventajas tiene esta implementación?

  • Optimización: Reduce la carga sobre los recursos del servidor al limitar las llamadas a la API.
  • Performance: Mejora el rendimiento al minimizar la cantidad de lógica que React necesita controlar en cada renderizado.
  • Simplicidad: El uso de useCallback elimina la necesidad de gestionar manualmente la instancia de la función entre renders.

¿Por qué podría preferir usar useRef?

useRef también mantiene valores persistentes entre renders sin provocar re-renderizados adicionales. Puedes explorarlo si prefieres una solución alternativa o deseas manipular la instancia de la función directamente.

import { useRef, useEffect } from 'react';
import debounce from 'lodash/debounce';

const DebouncedComponent = () => {
  const searchRef = useRef(
    debounce((searchTerm) => {
      console.log('Searching:', searchTerm);
    }, 300)
  );

  useEffect(() => {
    const debouncedSearch = searchRef.current;

    return () => {
      debouncedSearch.cancel();
    };
  }, []);

  return (
    <input
      type="text"
      onChange={(e) => searchRef.current(e.target.value)}
    />
  );
}

Poner en práctica estas técnicas no solo optimiza nuestra aplicación, sino que también nos permite gestionar las interacciones del usuario de una manera mucho más fluida y eficiente. ¡Continúa explorando y practicando para dominar estos conceptos avanzados!