Busque em todas as páginas da documentação
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
# Versão do módulo ES com tree-shaking (recomendado)
npm install lodash-es
npm install -D @types/lodash-es
# Ou versão clássica com importações selecionadas
npm install lodash
npm install -D @types/lodash// Importe funções individuais para tree-shaking
import debounce from "lodash-es/debounce";
import groupBy from "lodash-es/groupBy";
import cloneDeep from "lodash-es/cloneDeep";
// Ou importações nomeadas (funciona com lodash-es)
import { debounce, groupBy, cloneDeep } from "lodash-es";Quando usar isso: Você precisa de funções utilitárias confiáveis para debounce, throttle, clonagem profunda, agrupamento ou mesclagem que lidam com casos extremos melhor do que soluções rápidas feitas manualmente.
// app/components/SearchWithDebounce.tsx
"use client";
import { useState, useCallback, useMemo, useEffect } from "react";
import debounce from "lodash-es/debounce";
import groupBy from "lodash-es/groupBy";
interface Product {
id: number;
name: string;
category: string;
price: number;
}
const ALL_PRODUCTS: Product[] = [
{ id: 1, name: "Manual do React", category: "livros", price: 29 },
{ id: 2, name: "Guia de TypeScript", category: "livros", price: 35 },
{ id: 3, name: "Teclado Mecânico", category: "eletrônicos", price: 150 },
{ id: 4, name: "Hub USB-C", category: "eletrônicos", price: 45 },
{ id: 5, name: "Mesa Ajustável", category: "móveis", price: 400 },
{ id: 6, name: "Braço para Monitor", category: "móveis", price: 80 },
];
export default function SearchWithDebounce() {
const [query, setQuery] = useState("");
const [results, setResults] = useState<Product[]>(ALL_PRODUCTS);
const searchProducts = useMemo(
() =>
debounce((searchQuery: string) => {
const filtered = ALL_PRODUCTS.filter((p) =>
p.name.toLowerCase().includes(searchQuery.toLowerCase())
);
setResults(filtered);
}, 300),
[]
);
// Limpa o debounce ao desmontar
useEffect(() => {
return () => {
searchProducts.cancel();
};
}, [searchProducts]);
const handleChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => {
setQuery(e.target.value);
searchProducts(e.target.value);
},
[searchProducts]
);
const grouped = groupBy(results, "category");
return (
<div className="max-w-lg mx-auto p-6">
<input
value={query}
onChange={handleChange}
placeholder="Pesquisar produtos..."
className="w-full border rounded px-3 py-2 mb-4"
/>
{Object.entries(grouped).map(([category, items]) => (
<div key={category} className="mb-4">
<h3 className="font-bold capitalize text-lg">{category}</h3>
<ul className="mt-1 space-y-1">
{items.map((item) => (
<li key={item.id} className="flex justify-between">
<span>{item.name}</span>
<span className="text-gray-500">${item.price}</span>
</li>
))}
</ul>
</div>
))}
<p className="text-sm text-gray-400 mt-4">
{results.length} resultados encontrados
</p>
</div>
);
}O que isto demonstra:
groupBy para organizar resultados por categoriauseMemo para criar uma referência estável para a função debouncedlodash-es fornece exportações de módulos ES, permitindo que bundlers (webpack, Rollup, esbuild) façam tree-shake de funções não utilizadasdebounce atrasa a execução da função até que um tempo de espera especificado tenha passado desde a última chamada; cancel() impede invocações pendentesthrottle limita a execução a no máximo uma vez por intervalo, útil para manipuladores de scroll/resizegroupBy cria um objeto onde as chaves vêm do iterável e os valores são arrays de elementos correspondentescloneDeep copia recursivamente objetos, incluindo objetos aninhados, arrays, Maps, Sets e instâncias de Datemerge faz deep-merge de objetos, enquanto Object.assign e spread fazem apenas shallow mergeThrottle para manipuladores de scroll/resize:
"use client";
import { useEffect, useState } from "react";
import throttle from "lodash-es/throttle";
export function useScrollPosition() {
const [scrollY, setScrollY] = useState(0);
useEffect(() => {
const handleScroll = throttle(() => {
setScrollY(window.scrollY);
}, 100);
window.addEventListener("scroll", handleScroll);
return () => {
handleScroll.cancel();
window.removeEventListener("scroll", handleScroll);
};
}, []);
return scrollY;
}Deep merge de objetos de configuração:
import merge from "lodash-es/merge";
const defaultConfig = {
theme: { colors: { primary: "#3b82f6", secondary: "#64748b" } },
features: { darkMode: false, notifications: true },
};
const userConfig = {
theme: { colors: { primary: "#ef4444" } },
features: { darkMode: true },
};
const config = merge({}, defaultConfig, userConfig);
// { theme: { colors: { primary: "#ef4444", secondary: "#64748b" } },
// features: { darkMode: true, notifications: true } }Clonagem profunda segura:
import cloneDeep from "lodash-es/cloneDeep";
const original = {
nested: { value: 42, date: new Date(), set: new Set([1, 2, 3]) },
};
const copy = cloneDeep(original);
copy.nested.value = 100;
console.log(original.nested.value); // 42 (inalterado)Outros utilitários comuns:
import pick from "lodash-es/pick";
import omit from "lodash-es/omit";
import uniqBy from "lodash-es/uniqBy";
import chunk from "lodash-es/chunk";
import get from "lodash-es/get";
// Seleciona chaves específicas de um objeto
const user = { id: 1, name: "Alice", email: "alice@example.com", password: "secret" };
const safe = pick(user, ["id", "name", "email"]);
// Remove chaves
const noPassword = omit(user, ["password"]);
// Deduplica por uma propriedade
const unique = uniqBy(users, "email");
// Divide array em páginas
const pages = chunk(items, 10); // [[...10], [...10], ...]
// Acesso seguro a propriedades profundas (considere encadeamento opcional em vez disso)
const value = get(config, "deeply.nested.value", "default");@types/lodash-es fornece definições de tipo completas para todas as funçõesdebounce e throttle retornam DebouncedFunc<T> com métodos cancel() e flush()groupBy retorna Dictionary<T[]> onde as chaves são stringsimport type { DebouncedFunc } from "lodash-es";
// Função debounced explicitamente tipada
const debouncedSearch: DebouncedFunc<(query: string) => void> = debounce(
(query: string) => {
console.log("Buscando:", query);
},
300
);Importar todo o lodash - import _ from "lodash" agrupa toda a biblioteca (cerca de 70KB minificado). Correção: Use lodash-es com importações nomeadas ou importe caminhos específicos como lodash-es/debounce.
Debounce no render - Criar uma função debounced dentro do render cria uma nova instância a cada renderização, derrotando o propósito. Correção: Envolva com useMemo ou useCallback e forneça uma referência estável.
Vazamentos de memória de debounce/throttle - Chamadas debounced pendentes podem disparar após o componente ser desmontado. Correção: Chame .cancel() na função de limpeza do useEffect.
cloneDeep é caro - Clonar profundamente objetos grandes é lento. Correção: Use structuredClone() (nativo, disponível em todos os navegadores modernos e Node 17+) para casos simples. Use cloneDeep apenas quando precisar lidar com funções ou recursos especiais do Lodash.
get vs encadeamento opcional - _.get(obj, "a.b.c") é redundante agora que o JavaScript tem obj?.a?.b?.c. Correção: Prefira encadeamento opcional para acesso a propriedades. Use get apenas quando o caminho for dinâmico (uma variável).
merge modifica o alvo - merge(target, source) modifica target. Correção: Passe um objeto vazio como primeiro argumento: merge({}, defaults, overrides).
| Função | Alternativa Nativa | Quando Usar Lodash |
|---|---|---|
cloneDeep | structuredClone() | Ao clonar funções ou instâncias de classe |
get | Encadeamento opcional (?.) | Quando o caminho é uma variável de string dinâmica |
debounce | Nenhuma alternativa nativa | Sempre (ou use um pequeno pacote use-debounce) |
throttle | Nenhuma alternativa nativa | Sempre |
groupBy | Object.groupBy() (ES2024) | Ao segmentar ambientes mais antigos |
merge | Spread {...a, ...b} | Quando você precisa de deep merge (spread é shallow) |
uniqBy | [...new Map(arr.map(x => [x.key, x])).values()] | Quando a legibilidade importa |
chunk | Nenhuma alternativa nativa | Sempre |
lodash-es fornece exportações de módulos ES que os bundlers podem fazer tree-shakeimport { debounce } from "lodash" agrupa toda a biblioteca (~70KB)import { debounce } from "lodash-es" inclui apenas debounce e suas dependências@types/lodash-es junto para suporte a TypeScriptconst searchFn = useMemo(
() => debounce((query: string) => {
// realizar busca
}, 300),
[]
);
useEffect(() => {
return () => searchFn.cancel();
}, [searchFn]);Envolva em useMemo para uma referência estável. Limpe com .cancel() ao desmontar.
useMemo ou useCallback para que a mesma função debounced persista entre as renderizaçõesdebounce espera até N ms de inatividade antes de executar (bom para inputs de busca)throttle executa no máximo uma vez a cada intervalo de N ms (bom para manipuladores de scroll/resize).cancel() e .flush()merge modifica o primeiro argumento (o alvo)merge({}, defaults, overrides)defaults e overrides inalteradosstructuredClone() é nativo e lida com a maioria dos tipos (objetos, arrays, Maps, Sets, Dates)cloneDeep também lida com funções, RegExp com flags e wrappers específicos do lodashstructuredClone() para casos simples - nenhuma dependência necessáriacloneDeep ao clonar objetos que contêm funções ou instâncias de classeobj?.a?.b?.c - é nativo e type-safeget ainda é útil quando o caminho é uma variável dinâmica: get(obj, dynamicPath, defaultValue)get também suporta notação de array em caminhos: get(obj, "items[0].name")import type { DebouncedFunc } from "lodash-es";
const debouncedSearch: DebouncedFunc<(q: string) => void> =
debounce((q: string) => {
console.log("Buscando:", q);
}, 300);DebouncedFunc<T> adiciona .cancel() e .flush() ao tipo da função envolvida.
import groupBy from "lodash-es/groupBy";
const products = [
{ name: "Livro", category: "mídia" },
{ name: "CD", category: "mídia" },
{ name: "Mesa", category: "móveis" },
];
const grouped = groupBy(products, "category");
// { mídia: [...], móveis: [...] }Retorna Dictionary<T[]> onde as chaves são strings.
import omit from "lodash-es/omit";
const user = { id: 1, name: "Alice", password: "secret" };
const safe = omit(user, ["password"]);
// { id: 1, name: "Alice" }omit retorna um novo objeto; o original não é modificado.
import chunk from "lodash-es/chunk";
const items = [1, 2, 3, 4, 5, 6, 7];
const pages = chunk(items, 3);
// [[1, 2, 3], [4, 5, 6], [7]]Útil para paginação ou processamento em lote de requisições de API.
.cancel() na função de limpeza do useEffectdebounce quanto a throttleRevisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥