Hooks de React

React Hooks são funções poderosas que permitem o gerenciamento de estado e o tratamento do ciclo de vida em componentes funcionais — recursos que antes eram limitados a componentes de classe. Com hooks como useState para gerenciar o estado local e useEffect para lidar com efeitos colaterais, os desenvolvedores podem escrever código mais limpo e modular. Os hooks promovem a reutilização, permitindo encapsular a lógica com estado, ao mesmo tempo em que aderem a regras específicas — como chamar hooks apenas no nível superior e sempre prefixá-los com "use" — para manter um comportamento previsível e consistente.

Abaixo, uma coleção selecionada de React Hooks úteis, desenvolvidos especificamente para uso em vários projetos, integrações e widgets da Kommo.

Instalação

As opções de instalação estão disponíveis no repositório público do GitHub.

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

Hooks

useConst

Este hook foi projetado para ser usado no lugar do useMemo com um array vazio de dependências.

React hook que memoriza o valor retornado pela função fn sempre que o Componente for chamado. Ele garante que o valor seja salvo entre as renderizações do componente para evitar a necessidade de recálculo e recriação do valor sempre que o componente for atualizado.

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 custo...");
    return Math.random();
  });

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

Referência

const value = useConst(fn: () =>);
  • value- valor imutável obtido de uma chamada de função;
  • fn: () => - retorno de chamada que será chamado e valor de retorno

useDebounce

React Hook que adia as mudanças de estado até que tenham decorrido milissegundos de espera desde a última vez que a função debounce foi invocada. O atraso de debounce começará quando um dos valores mudar.

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>
  );
};

Referência

const debouncedValue = useDebounce(value: T, delay: number);
  • debouncedValue - valor atual atrasado;
  • value: T - valor cuja alteração aciona o atraso;
  • delay: number - tempo de espera em milissegundos;

useDidUpdateEffect

React hook que permite executar um efeito somente após a primeira renderização e todas as renderizações subsequentes. Este hook emula o comportamento 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("Efeito acionado após a renderização inicial");
  }, [count]);

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

Referência

useDidUpdateEffect(fn: () =>, inputs?: React.DependencyList): void;
  • fn: () => - função que será chamada;
  • inputs: DependencyList - array de valores dos quais a chamada da função depende, da mesma forma que useEffect;

useKeyboardListNavigation

React hook que gerencia a navegação por teclado para uma lista de itens. Ele fornece funcionalidade para navegar para cima e para baixo na lista usando as teclas de seta, selecionar um item e alternar um 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>
  );
};

Referência

const { currentHoveredIndex, onKeyDown, updateListPosition, } = useKeyboardListNavigation(
  options: UseKeyboardListNavigationOptions);
  • currentHoveredIndex: number - o índice do item atualmente em foco;
  • onKeyDown: (event: React.KeyboardEvent) => void - função manipuladora para eventos de teclado;
  • updateHoveredIndex: (index: number) => void - função para atualizar o índice de foco;
  • updateListPosition: (index: number) => void - função para atualizar o índice de foco e a posição na lista;

useIsComponentMounted

Este hook foi projetado para evitar atualizações de estado em componentes não montados.

Um React hook que retorna uma função para determinar se o componente está montado no momento.

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);
  }, []);
};

Referência

const isMounted = useIsComponentMounted(): (() => boolean);
  • isMounted: Function - função que retornará verdadeiro se o componente estiver montado e falso caso contrário;

useOnOutsideClick

Este hook foi projetado para rastrear um clique fora do elemento DOM passado.

Hook personalizado que manipula cliques fora de um elemento especificado.

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>
  );
};

Referência

const useOnOutsideClick: ({
  ref,
  handler,
  context,
}: UseOnOutsideClickOptions) => void;
  • ref: MutableRefObject<HTMLElement> - elemento DOM de referência, cliques fora do qual serão rastreados e processados ​​pelo manipulador;
  • handler: Function - função que será chamada ao clicar fora da referência;
  • context: string - contexto para agrupar manipuladores e itens rastreados. Se especificado, manipuladores e links serão agrupados dentro do contexto especificado. Manipuladores de um contexto não afetarão manipuladores de outros contextos. global - contexto geral usado por padrão.

useDeepCompareEffect

React hook que permite executar um efeito somente quando as dependências mudam profundamente. Este hook é útil quando você deseja evitar execuções desnecessárias de efeitos devido à comparação superficial de dependências.

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("Efeito acionado devido a uma mudança profunda nas dependências");
  }, [data]);

  useEffect(() => {
    console.log("Efeito acionado devido a uma mudança comum nas dependências");
  }, [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>
  )
};