惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
L
LangChain Blog
博客园 - 【当耐特】
I
InfoQ
腾讯CDC
人人都是产品经理
人人都是产品经理
H
Help Net Security
Y
Y Combinator Blog
B
Blog
博客园 - Franky
Microsoft Security Blog
Microsoft Security Blog
Stack Overflow Blog
Stack Overflow Blog
The Cloudflare Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
H
Hackread – Cybersecurity News, Data Breaches, AI and More
博客园 - 叶小钗
D
Docker
博客园 - 聂微东
B
Blog RSS Feed
G
Google Developers Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
I Built a Tool That Shows You Exactly Why a React Compone...
Devanshu Biswas · 2026-06-26 · via DEV Community

Devanshu Biswas

"Why did this component re-render?" is the React question everyone asks and almost no one can answer at a glance — because the answer is invisible. So I built a tool that makes it visible.

▶ Live demo: https://react-render-visualizer.vercel.app/
Source (React 19 + TS + Vite): https://github.com/dev48v/react-render-visualizer

The component tree on screen is a real React tree. Every node flashes when it actually renders, counts its renders, and labels why it rendered. A side panel keeps a running wasted renders counter.

The three rules, made visible

There are really only three reasons a component re-renders, and the tool shows each one:

  1. A parent re-render re-renders all of its children — by default. With React.memo off, click the tick++ button and the entire tree flashes, even components whose props never changed. The wasted counter climbs.
  2. React.memo skips the re-render when props are unchanged. Turn memo on, click tick++ → only Content → Counter re-render (they're the ones that actually use tick); Header and Sidebar skip. Wasted renders: 0.
  3. A fresh object/array/function prop defeats memo. Turn "stable props" off so the parent hands down a brand-new style object every render, and click again → Sidebar and Content re-render despite being memoized, because memo's shallow compare sees a changed reference. That's the useMemo/useCallback lesson, concrete.
memo stable props tick++ re-renders
off everything
on on only Content → Counter
on off Sidebar + Content too (new style ref)

How it's built

The whole thing hinges on a small hook:

function useTracker(name: string, watch: Record<string, unknown>) {
  const n = useRef(0);
  const prev = useRef(watch);
  n.current++;

  let reason: string;
  if (n.current === 1) reason = "mount";
  else {
    const changed = Object.keys(watch).filter(k => watch[k] !== prev.current[k]);
    reason = changed.length
      ? "props changed: " + changed.join(", ")
      : "parent re-rendered (no prop change)";
  }
  prev.current = watch;

  useEffect(() => { record(name, reason); /* + flash the node */ });
  return reason;
}

It diffs this render's watched props against the previous render to classify the cause. One subtlety worth stealing: the render events go into a tiny external store read with useSyncExternalStore, not React state. If the panels used useState, recording a render would itself trigger renders and pollute the very counts you're measuring. An external store updates the panels without re-rendering the tree under test.

No StrictMode, on purpose — StrictMode intentionally double-invokes render in dev, which would double every count.

Why a playground beats an article (even this one)

You can read "memo does a shallow prop comparison" ten times and still ship a style={{...}} that silently breaks it. Clicking a button and watching the wasted counter jump from 0 to 12 the instant you pass an inline object teaches it in one go.

One npm install, zero UI dependencies. If it made re-renders click for you, a star helps others find it: https://github.com/dev48v/react-render-visualizer