Skip to content

Guide · Open source

How to use why-did-you-render: find avoidable React re-renders

Updated · written with AI from the project's own documentation and checked against our catalogue data

why-did-you-render is an open-source MIT-licensed JavaScript library that hooks into React and logs when a component re-renders even though its props or state did not meaningfully change. It is aimed at developers tracking down performance problems in React and React Native apps. This guide shows you how to install it, configure it, track components and custom hooks, and know when its output is worth acting on.

why-did-you-renderwelldone-software/why-did-you-render · ★ 12.5k · MIT

Quick start

  1. 1Install the package. Add @welldone-software/why-did-you-render as a dev dependency with npm or yarn.
  2. 2Set the Babel JSX import source. Configure preset-react with runtime automatic, development mode and the library as importSource.
  3. 3Create wdyr.js. Call whyDidYouRender(React, options) only when NODE_ENV is development.
  4. 4Import it first. Import wdyr as the very first import in your entry file.
  5. 5Choose what to track. Use trackAllPureComponents or set whyDidYouRender = true on specific components.
  6. 6Check the logs and measure. Look at the logged re-render notices and confirm improvements with the React DevTools Profiler.

Install why-did-you-render as a dev dependency

Install the package as a development dependency using npm or yarn. You need Node.js and either npm or yarn, plus a Babel setup that includes @babel/preset-react or an equivalent JSX transform.

  • npm: install it with --save-dev
  • yarn: install it with -D
npm install @welldone-software/why-did-you-render --save-dev yarn add @welldone-software/why-did-you-render -D

Configure Babel to use the library as the JSX import source

Set the library as the React importSource and make sure preset-react runs in development mode. The README notes that React 19 requires the automatic JSX transformation, so runtime is set to automatic. Use this with your babel config.

  • runtime must be 'automatic' for React 19
  • development should be true only in development builds
  • importSource points to @welldone-software/why-did-you-render
['@babel/preset-react', { runtime: 'automatic', development: process.env.NODE_ENV === 'development', importSource: '@welldone-software/why-did-you-render', }]

Create wdyr.js and import it first

Create a file named wdyr.js. It enables the library only in development and passes React to it. Set trackAllPureComponents to true to track every React.PureComponent and React.memo component. Then import this file as the very first import in your app, before any other import, including react-hot-loader if you use it.

  • Use the file name wdyr.ts with a reference types line if you use TypeScript
  • Import './wdyr' at the top of index.js
import React from 'react'; if (process.env.NODE_ENV === 'development') { const whyDidYouRender = require('@welldone-software/why-did-you-render'); whyDidYouRender(React, { trackAllPureComponents: true, }); }

Track specific components and custom hooks

If you do not use trackAllPureComponents, add whyDidYouRender = true to the components you want to track. For a class component, set it as a static property. To track custom hooks such as useSelector from React Redux, pass them in the trackExtraHooks option.

The README warns that rewriting exports of imported files in webpack can cause a problem with trackExtraHooks, with a workaround discussed in the linked issue #85.

  • Ad hoc tracking: Component.whyDidYouRender = true
  • Hook tracking: trackExtraHooks: [[ReactRedux, 'useSelector']]
class BigList extends React.Component { static whyDidYouRender = true render(){ return ( //some heavy render you want to ensure doesn't happen if its not necessary

Use it with React Native, Metro or Expo

For a bare React Native project, add the JSX transform plugin inside the development env block of your babel config and start the packager as usual. The README says the default Babel env is development. In Expo managed projects, pass jsxImportSource to babel-preset-expo instead. In the wdyr.js file, you may prefer the __DEV__ flag over process.env.NODE_ENV.

  • Bare workflow: plugin under env.development
  • Expo managed: jsxImportSource in babel-preset-expo options
  • Create React App 4 already uses the automatic JSX transform; the README links a comment with the steps for CRA

Read the output and decide what to fix

The library prints notices when a component re-renders without meaningful prop or state changes. A common case the README gives is an inline style object such as style={{width: '100%'}} passed to a large memo component, which creates a new object on every render and so always re-renders.

The README also cautions that not every re-render is a problem. Focus on heavier components first, and use the React DevTools Profiler to measure whether a change actually helps.

  • Start with large or expensive components
  • Confirm the gain with the React DevTools Profiler before refactoring
  • Do not optimize every re-render; it can add complexity without benefit

Know the limits before you start

Only use the library in development. The README says it significantly slows down React and monkey patches it, which can cause unexpected behavior. Mobx is not supported according to the README, and the library was not tested with React Compiler, which the author believes is incompatible.

Version matters. The latest version is tested with React 19 only. For React 18 use the version 8 branch, and for React 16 or 17 use the version 7 branch.

  • Not for production builds
  • Not tested with React Compiler
  • Mobx is not supported
  • React 18: use the version 8 branch; React 16/17: use the version 7 branch

What people use it for

  • Finding why a large memo list re-renders after an inline style object changes
  • Tracking how often a component using React Redux useSelector re-renders
  • Checking pure components across a React Native screen during development
  • Auditing which heavy components re-render unnecessarily before refactoring

Frequently asked questions

Is why-did-you-render free to use?

Yes, it is released under the MIT licence, according to the repository. You can use and modify it under those terms.

How do I install why-did-you-render?

Run npm install @welldone-software/why-did-you-render --save-dev, or yarn add @welldone-software/why-did-you-render -D. Install it as a development dependency.

Can I use why-did-you-render in production?

No. The README says it should never be used in production because it significantly slows React down and monkey patches it, which can cause unexpected behavior. Keep it behind a development check.

Does why-did-you-render work with React Native?

Yes, the README says it works with React Native. Bare workflow projects add the JSX plugin in the development env block of the Babel config, and Expo managed projects pass jsxImportSource to babel-preset-expo.

Which React versions does it support?

The latest version is tested with React 19. For React 18 use the version 8 branch, and for React 16 or 17 use the version 7 branch, as linked in the README.

What are the alternatives to why-did-you-render?

The README points to the React DevTools Profiler for measuring the effect of changes. Other projects in the same space include react-scan and why-did-you-update.

New agent skills, repos and AI tools — every week

The best new skills and open-source projects, the fastest-growing repos, and one free prompt. Five minutes to read. Unsubscribe anytime.

Our verdict

why-did-you-render suits React and React Native developers who are debugging slow screens and want to see which memoized or pure components re-render without meaningful changes. Skip it if you use React Compiler, Mobx, or need something for production, and consider the React DevTools Profiler for measuring real performance gains.

Install options & downloads