why-did-you-render
Monkey-patches React to flag avoidable re-renders caused by unchanged props, state, or hooks.
Repository Health
Technical Analysis
@welldone-software/why-did-you-render patches React’s createElement, cloneElement, and core hooks to watch every component render and report when that render was technically avoidable — when props, state, or hook results were deeply equal to the previous render but still triggered a re-render because of referential inequality, such as a new object or function literal created on every parent render. It works with class components, function components, memoized components, and forwardRef components, and can track custom hooks such as react-redux’s useSelector.
Because the library hooks directly into React’s element-creation and hook APIs rather than relying on the Profiler API, it can pinpoint the exact prop, state, or hook path that changed and print a readable console diff of the before/after values. It’s meant strictly for local development — the README explicitly warns against production use, since the patching adds overhead and can produce unexpected behavior — and it supports React Native as well as web React.
What You Get
- Console warnings showing exactly which prop, state, or hook value changed (or didn’t) on every avoidable re-render, including a readable diff of before/after values.
- Support for all four React component shapes — class components, function components, React.memo, and forwardRef — through dedicated patch modules.
- Hook-level tracking for React’s built-in useState, useReducer, useContext, and useMemo/useCallback, plus the ability to track custom hooks like react-redux’s useSelector via trackExtraHooks.
- Configurable notifier, include/exclude regex filters, and per-component opt-in via a static whyDidYouRender flag, so tracking can be scoped to just the components you’re debugging.
Common Use Cases
- Diagnosing why a big memoized list or table component keeps re-rendering despite using React.memo or PureComponent.
- Finding call sites that pass new object/array/function literals as props on every parent render, defeating memoization.
- Auditing a component tree after introducing a custom hook like react-redux’s useSelector to confirm it isn’t causing extra hook-driven re-renders.
- Verifying the effect of a performance optimization (memoization, useCallback, useMemo) by confirming avoidable re-renders drop to zero.
Under The Hood
Architecture whyDidYouRender (src/whyDidYouRender.js) monkey-patches React.createElement, React.createFactory, and React.cloneElement so every element creation for a supported component type is routed through a tracking layer; getWDYRType decides whether a given component type should be tracked (via shouldTrack) and dispatches to one of four dedicated patch modules under src/patches/ — patchClassComponent, patchFunctionalOrStrComponent, patchMemoComponent, and patchForwardRefComponent — each wrapping the component so its render is compared against the previous one via getUpdateInfo and calculateDeepEqualDiffs. Shared mutable state (the original React methods, per-run hook info, per-component patched wrappers) lives in a single wdyrStore singleton, and trackHooksIfNeeded separately rewrites React’s useState/useReducer/useContext/useSyncExternalStore/useMemo/useCallback (plus any hooks passed via trackExtraHooks) to funnel hook-level changes through the same reporting path. The whole patch is reversible at runtime through an injected React.REVERT_WHY_DID_YOU_RENDER function.
Tech Stack The library is authored in plain JavaScript (97% of the codebase) with hand-written TypeScript declaration files (types.d.ts, jsx-runtime.d.ts) for consumers, targeting React 19 as a peer dependency and using lodash as its sole runtime dependency for small utilities like get/isFunction. It’s built with Babel (@babel/preset-env, @babel/preset-react) and bundled with Rollup into a single dist/whyDidYouRender.js CommonJS entry point, with Nollup powering a live-reloading demo app served via Express (demo/serve.js) for manual testing against React, React Redux, and React Router.
Code Quality
The tests/ directory mirrors src/ file-for-file, with dedicated Jest specs for calculateDeepEqualDiffs, defaultNotifier, findObjectsDifferences, getDisplayName, getUpdateInfo, normalizeOptions, and shouldTrack, plus separate suites for hook tracking, strict-mode behavior, and a librariesTests/ folder covering integration with libraries like react-redux — an extensive test surface for a project this size. End-to-end coverage is added via Cypress against the demo app. Linting runs through a flat ESLint config with the React and Cypress plugins and --max-warnings 0 enforced in CI, though the library itself is untyped JavaScript rather than compiled TypeScript, so type safety for internal code relies on convention and the hand-maintained .d.ts files rather than compiler enforcement.
What Makes It Unique Rather than surfacing timing data the way React’s built-in Profiler API does, why-did-you-render patches React’s own element-creation and hook internals to do structural, path-level diffing of props, state, and hook results, letting it tell you specifically whether a re-render was avoidable (deeply equal inputs, different reference) versus a legitimate change — and to extend that same diffing to arbitrary custom hooks like a Redux selector via trackExtraHooks. That focus on causal, per-value diagnosis rather than aggregate timing is a distinctive technical choice for a React performance-debugging tool.
Used by 6 apps in this directory
Appsmith
Developer Tools · Automation · No Code Platforms
Open-source low-code platform to build admin panels, dashboards, and internal tools connected to any database or API.
Automatisch
Automation · No Code Platforms
Self-hosted, no-code workflow automation that keeps your data on your own servers—a privacy-first alternative to Zapier with 90+ integrations.
Bigcapital
Invoicing Finance
Self-hostable double-entry accounting platform with invoicing, inventory, multi-currency, and real-time financial reporting for small and medium businesses.
Grafana
Monitoring · Analytics
The open-source observability platform that unifies metrics, logs, and traces from any data source into dynamic, queryable dashboards.
LibrePhotos
File Storage
Self-hosted photo library with AI-powered face recognition, semantic search, and automatic event albums — no cloud required.
Twake Drive
File Storage · Collaboration
Open-source, self-hosted file manager with collaborative drives, AI-powered summarization, and OnlyOffice document editing for teams who want full data sovereignty.