Hooks de React

Los Hooks de React son funciones poderosas que permiten gestionar el estado y el ciclo de vida dentro de componentes-capacidades funcionales que anteriormente estaban limitadas a los componentes de clase. Con hooks como useState para gestionar el estado local y useEffect para manejar efectos secundarios, los desarrolladores pueden escribir código más limpio y modular. Los hooks promueven la reutilización al permitir encapsular lógica con estado, respetando reglas específicas, como llamarlos solo en el nivel superior del componente y siempre comenzar sus nombres con “use” - para mantener un comportamiento predecible y consistente.

A continuación, se presenta una colección seleccionada de hooks útiles de React desarrollados específicamente para su uso en distintos proyectos, integraciones y widgets de Kommo.

Instalación

Las opciones de instalación están disponibles en el repositorio público de GitHub.

npmyarnpnpm
npm i @kommo-crm/react-hooksyarn add @kommo-crm/react-hookspnpm add @kommo-crm/react-hooks

Hooks

useConst

Este hook está diseñado para utilizarse en lugar de useMemo con un arreglo vacío de dependencias

Es un hook de React que memoriza el valor retornado por la función fn cada vez que se llama al Component. Garantiza que el valor se conserve entre renderizados del componente para evitar recalcular y recrear el valor cada vez que el componente se actualiza.

Uso

import React from 'react';
import { useConst } from '@kommo-crm/react-hooks';

const Demo: React.FC = () => {
  const value = useConst<number>(() => {
    console.log("Calculando valor de alto costo...");
    return Math.random();
  });

  return (
    <div>
      <p>Value: {value}</p>
    </div>
  );
};

Referencia

const value = useConst(fn: () =>);
  • value- valor inmutable obtenido a partir de la llamada a una función;
  • fn: () => - callback que será llamado y retornará un valor;

useDebounce

Hook de React que demora los cambios de estado hasta que hayan pasado los milisegundos especificados desde la última vez que se invocó la función con debounce. La espera comienza cuando alguno de los valores cambia.

Uso

import React, { useState, ChangeEvent } from 'react';
import { useDebounce } from '@kommo-crm/react-hooks';

const Demo: React.FC = () => {
  const [searchTerm, setSearchTerm] = useState("");
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
    setSearchTerm(e.target.value);
  };

  return (
    <div>
      <h1>Debounced Search</h1>
      <input
        type="text"
        placeholder="Buscar..."
        value={searchTerm}
        onChange={handleChange}
      />
      <p>Searching for: {debouncedSearchTerm}</p>
    </div>
  );
};

Referencia

const debouncedValue = useDebounce(value: T, delay: number);
  • debouncedValue - valor actual demorado;
  • value: T - valor cuyo cambio activa la demora
  • delay: number - tiempo de espera en milisegundos;

useDidUpdateEffect

Hook de React que permite ejecutar un efecto solo después del primer renderizado y en todos los renderizados siguientes. Este hook emula el comportamiento de componentDidUpdate.

Uso

import React,{useState} from 'react';
import { useDidUpdateEffect } from '@kommo-crm/react-hooks';

const Demo: React.FC = () => {
  const [count, setCount] = useState(0);

  useDidUpdateEffect(() => {
    console.log("Efecto que se activa después del renderizado inicial");
  }, [count]);

  return (
    <div>
      <h1>useDidUpdateEffect Example</h1>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment Count</button>
    </div>
  )
};

Referencia

useDidUpdateEffect(fn: () =>, inputs?: React.DependencyList): void;
  • fn: () => - función que será llamada;
  • inputs: DependencyList - arreglo de valores del que depende la ejecución de la función, igual que en useEffect;

useKeyboardListNavigation

Hook de React que gestiona la navegación por teclado en una lista de elementos. Proporciona funcionalidades para navegar hacia arriba y abajo en la lista utilizando las teclas de flecha, seleccionar un elemento y alternar un estado.

Uso

import React, { useState } from 'react';
import { useKeyboardListNavigation } from '@kommo-crm/react-hooks';

const Demo: React.FC = () => {
  const items = ['Item 1', 'Item 2', 'Item 3'];
  const [isOpen, setIsOpen] = useState(true);

  const { currentHoveredIndex, onKeyDown, updateListPosition } = useKeyboardListNavigation({
    itemsLength: items.length,
    isOpened: isOpen,
    hoveredIndex: 0,
    onSelect: (index) => alert(`Selected: ${items[index]}`),
    onToggle: () => setIsOpen((prev) => !prev),
  });

  return (
    <div onKeyDown={onKeyDown} tabIndex={0}>
      <h1>Keyboard Navigation</h1>
      {isOpen && (
        <ul>
          {items.map((item, index) => (
            <li
              key={item}
              style={{
                background: index === currentHoveredIndex ? 'lightblue' : 'transparent',
              }}
            >
              {item}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
};

Referencia

const { currentHoveredIndex, onKeyDown, updateListPosition, } = useKeyboardListNavigation(
  options: UseKeyboardListNavigationOptions);
  • currentHoveredIndex: number - índice del elemento que se encuentra enfocado
  • onKeyDown: (event: React.KeyboardEvent) => void - función handler para eventos de teclado;
  • updateHoveredIndex: (index: number) => void - función para actualizar el índice del elemento enfocado;
  • updateListPosition: (index: number) => void - función para actualizar el índice enfocado y la posición en la lista;

useIsComponentMounted

Este hook está diseñado para evitar actualizaciones de estado en componentes desmontados.

Es un hook de React que retorna una función para determinar si el componente está montado.

Uso

import React from 'react';
import { useIsComponentMounted } from '@kommo-crm/react-hooks';

const Demo: React.FC = () => {
  const isMounted = useIsComponentMounted();

  useEffect(() => {
    setTimeout(() => {
      if (isMounted()) {
        // ...
      } else {
        // ...
      }
    }, 1000);
  }, []);
};

Referencia

const isMounted = useIsComponentMounted(): (() => boolean);
  • isMounted: Function - función que retorna true si si el componente está montado y flase en caso contrario.

useOnOutsideClick

Este hook está diseñado para detectar clics fuera del elemento del DOM proporcionado.

Hook personalizado que maneja los clics fuera de un elemento específico.

Uso

import React, { useRef } from 'react';
import { useOnOutsideClick } from '@kommo-crm/react-hooks';

const Demo: React.FC = () => {
  const ref = useRef<HTMLDivElement>(null);

  useOnOutsideClick({
    ref,
    handler: (event) => {
      console.log('Clicked outside the element', event);
    },
  });

  return (
    <div>
      <div ref={ref} style={{ padding: '20px', background: '#f0f0f0' }}>
        Click inside this box
      </div>
      <p>Click outside the box to trigger the handler.</p>
    </div>
  );
};

Referencia

const useOnOutsideClick: ({
  ref,
  handler,
  context,
}: UseOnOutsideClickOptions) => void;
  • ref: MutableRefObject<HTMLElement> - elemento del DOM cuya referencia se utiliza para rastrear clics fuera de él;
  • handler: Function - función que se ejecuta al hacer clic fuera del elemento referenciado;
  • context: string - contexto para agrupar funciones y elementos rastreados. Si se especifica, los handlers y elementos se agrupan dentro del contexto indicado. Los handlers de un contexto no afectan a los de otros.
    global - contexto general utilizado por defecto.

useDeepCompareEffect

Hook de React que permite ejecutar un efecto solo cuando las dependencias cambian en profundidad. Este hook es útil cuando se desea evitar ejecuciones innecesarias del efecto debido a comparaciones superficiales de las dependencias.

Uso

import React, { useState } from 'react';
import { useDeepCompareEffect } from '@kommo-crm/react-hooks';

const Demo: React.FC = () => {
  const [data, setData] = useState({ count: 0 });

  useDeepCompareEffect(() => {
    console.log("Efecto activado por un cambio profundo en las dependencias");
  }, [data]);

  useEffect(() => {
    console.log("Efecto activado por un cambio superficial en las dependencias");
  }, [data]);

  return (
    <div>
      <h1>useDeepCompareEffect Example</h1>
      <p>Count: {data.count}</p>
      <button onClick={() => setData({ count: data.count + 1 })}>Increment Count</button>
      <button onClick={() => setData({ count: data.count })}>New object without effect</button>
    </div>
  )
};

Referencia