render-watch
v0.1.0
Published
A modern, developer-friendly library to detect and visualize React re-renders with Next.js App Router support
Downloads
104
Maintainers
Readme
render-watch
Uma biblioteca moderna e amigável para detectar e visualizar re-renders em React/Next.js com suporte completo para App Router
🎯 Por que render-watch?
Detectar re-renders desnecessários em React é difícil. As ferramentas existentes são:
- ❌ Pesadas e lentas (React DevTools Profiler)
- ❌ Desatualizadas (why-did-you-render não funciona com React 18+)
- ❌ Não suportam Next.js App Router
- ❌ Não mostram visualmente o problema
render-watch resolve isso oferecendo:
- ✅ Visualização em tempo real com bordas coloridas
- ✅ Logs detalhados no console
- ✅ Timeline interativa
- ✅ Detecção automática de padrões problemáticos
- ✅ Suporte completo para Next.js App Router + Server Components
- ✅ Zero configuração necessária
📦 Instalação
npm install render-watch
# ou
pnpm add render-watch
# ou
yarn add render-watch🚀 Uso Rápido
1. Configuração Básica (Next.js App Router)
// app/layout.tsx
"use client";
import { RenderWatchProvider } from "render-watch";
export default function RootLayout({ children }) {
return (
<html>
<body>
<RenderWatchProvider>{children}</RenderWatchProvider>
</body>
</html>
);
}2. Usando o Hook
"use client";
import { useRenderWatch } from "render-watch";
export function ProductList({ products, filters }) {
// Rastreia automaticamente todos os re-renders
useRenderWatch(
{ products, filters },
{
componentName: "ProductList",
}
);
return (
<div>
{products.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}3. Usando HOC (Higher-Order Component)
"use client";
import { withRenderWatch } from "render-watch";
function SearchBox({ query, onQueryChange }) {
return (
<input value={query} onChange={(e) => onQueryChange(e.target.value)} />
);
}
// Envolve o componente com tracking automático
export default withRenderWatch(SearchBox, {
componentName: "SearchBox",
showIndicator: true, // Mostra borda colorida
});🎨 Visualização
Bordas Coloridas
A biblioteca mostra automaticamente bordas coloridas nos componentes:
- 🔵 Azul: Render normal (1 render/segundo)
- 🟡 Amarelo: Render frequente (5+ renders/segundo)
- 🔴 Vermelho: Render excessivo (10+ renders/segundo)
Timeline
Uma sidebar aparece automaticamente mostrando:
- Histórico de renders
- Componente que renderizou
- Motivo do render
- Props que mudaram
- Timestamp
📊 Logs no Console
Nível Minimal
[ProductList] render #5Nível Detailed (padrão)
[ProductList] render #5
Reason: props-change
Changed props: filters, products
Parent rendered: falseNível Verbose
[ProductList] render #5
Reason: props-change
Changed props: filters, products
Props diff:
filters: {category: "electronics"} → {category: "electronics", price: "100"}
products: [...] → [...]
Parent rendered: false🔍 Detecção Automática de Problemas
A biblioteca detecta automaticamente padrões comuns:
⚠️ Objeto Inline em Props
⚠️ ProductList Object inline em props (filters)
💡 Sugestão: Use useMemo ou mova o estado para mais próximo do componente consumidor⚠️ Render em Cascata
⚠️ ProductList Render em cascata por props não memorizadas
💡 Sugestão: Use React.memo ou useMemo para evitar re-renders desnecessários⚠️ Loop de Render
⚠️ ProductList Loop de render detectado (23.5 renders/s)
💡 Sugestão: Verifique se há atualizações de estado dentro de render ou useEffect sem dependências⚙️ Configuração Avançada
<RenderWatchProvider
config={{
enabled: true,
showVisualIndicator: true,
showConsoleLogs: true,
showTimeline: true,
logLevel: "detailed", // 'minimal' | 'detailed' | 'verbose'
colorThresholds: {
normal: 1, // 1 render/segundo
frequent: 5, // 5 renders/segundo
excessive: 10, // 10+ renders/segundo
},
maxTimelineItems: 100,
detectPatterns: true,
}}
>
{children}
</RenderWatchProvider>🎯 Casos de Uso
Rastrear Componente Específico
function ExpensiveComponent({ data }) {
useRenderWatch(
{ data },
{
componentName: "ExpensiveComponent",
logProps: true,
}
);
// Seu componente aqui
}Desabilitar em Produção
<RenderWatchProvider
config={{
enabled: process.env.NODE_ENV === "development",
}}
>
{children}
</RenderWatchProvider>Rastrear Apenas em Desenvolvimento
function MyComponent(props) {
useRenderWatch(props, {
enabled: process.env.NODE_ENV === "development",
componentName: "MyComponent",
});
}🔧 API
Hooks
useRenderWatch(props, options)
Hook principal para rastrear re-renders.
Parâmetros:
props: Objeto com as props do componenteoptions:componentName?: string- Nome do componenteenabled?: boolean- Habilitar/desabilitar trackinglogProps?: boolean- Logar props no console
useWatchComponent(props, options)
Hook de alto nível que combina tracking com indicador visual.
Components
<RenderWatchProvider>
Provider que configura a biblioteca e renderiza a Timeline.
<RenderIndicator>
Componente que mostra borda colorida baseada na frequência de renders.
<Timeline>
Sidebar mostrando histórico de renders.
HOC
withRenderWatch(Component, options)
HOC que automaticamente rastreia renders do componente.
Store Utilities
import {
getRenders,
getComponentStats,
clearRenders,
updateConfig,
} from "render-watch";
// Obter todos os renders
const renders = getRenders();
// Obter estatísticas de um componente
const stats = getComponentStats().get("ProductList");
// Limpar histórico
clearRenders();
// Atualizar configuração
updateConfig({ logLevel: "verbose" });🚀 Next.js App Router
A biblioteca funciona perfeitamente com Next.js App Router:
// app/products/page.tsx
"use client";
import { useRenderWatch } from "render-watch";
export default function ProductsPage() {
useRenderWatch({}, { componentName: "ProductsPage" });
return <div>Products</div>;
}Nota: Componentes Server Components não re-renderizam no sentido tradicional, mas você pode usar trackServerComponentRender para debugging.
📝 Exemplos Completos
Exemplo 1: Lista de Produtos
"use client";
import { useRenderWatch } from "render-watch";
import { useMemo } from "react";
export function ProductList({ products, filters }) {
useRenderWatch(
{ products, filters },
{
componentName: "ProductList",
}
);
const filteredProducts = useMemo(() => {
return products.filter(
(p) => p.category === filters.category && p.price <= filters.maxPrice
);
}, [products, filters]);
return (
<div>
{filteredProducts.map((product) => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}Exemplo 2: Formulário com React Hook Form
"use client";
import { useForm } from "react-hook-form";
import { useRenderWatch } from "render-watch";
export function LoginForm() {
const { register, handleSubmit, watch } = useForm();
const formValues = watch();
useRenderWatch(formValues, {
componentName: "LoginForm",
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("email")} />
<input {...register("password")} />
<button type="submit">Login</button>
</form>
);
}🤝 Contribuindo
Contribuições são bem-vindas! Por favor, abra uma issue ou PR.
📄 Licença
MIT
🙏 Agradecimentos
Inspirado pela necessidade de uma ferramenta moderna e prática para debug de re-renders em React 18+ e Next.js App Router.
