Skip to content
why-did-you-render monkey patches React to notify you about avoidable re-renders.
Branch: master
Clone or download
vzaidman Merge pull request #45 from mostafah/patch-1
Fix typos in the log message
Latest commit 2df8ff0 Jul 4, 2019
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
demo fixed demo serving, strict mode demo and hot reload Jun 8, 2019
dist v3.2.1 Jun 18, 2019
src Fix typos in the log message Jul 4, 2019
.eslintignore using react hot reloader Dec 1, 2018
.eslintrc hooks works even if imported directly instead of using as React.useHook Apr 1, 2019
.gitignore improved examples, notifications Nov 16, 2018
.npmrc updated npm versioning message Nov 17, 2018
LICENSE initial working version 2.0.1 Nov 10, 2018
README.md Update README.md Apr 29, 2019
babel.config.js can use class properties in tests Jun 7, 2019
demo-image.png
package.json v3.2.1 Jun 18, 2019
rollup.config.js fixed no minified versions of no-classes-transpile created Apr 1, 2019
yarn.lock updated packages Jun 13, 2019

README.md

Why Did You Render

npm version

why-did-you-render monkey patches React to notify you about avoidable re-renders. (Works with React Native as well.)

For example, when you pass style={{width: '100%'}} to a big pure component and make it always re-render:

It can also help you to simply track when and why a certain component re-renders.

Read More

  • You can read more about the library >> HERE <<.
  • Part 2 - Common fixing scenarios this library can help to eliminate can be found >> HERE <<.
  • Part 3 - React Hooks - Understand and fix hooks issues >> HERE <<.
  • Part 4 - React-Redux - Understand and fix react-redux issues >> HERE <<.

Sandbox

You can test the library in the official sandbox >> HERE <<.

Setup

npm install @welldone-software/why-did-you-render --save

or

yarn add @welldone-software/why-did-you-render

Notice: the required React version for the library is >=16.8 but it might work with older versions by using trackHooks: false in whyDidYouRender's init options.

Installation

Execute whyDidYouRender with React as it's first argument.

import React from 'react';

if (process.env.NODE_ENV !== 'production') {
  const whyDidYouRender = require('@welldone-software/why-did-you-render');
  whyDidYouRender(React);
}

If you are building for latest browsers and don't transpile the "class" keyword use the "no-classes-transpile" dist:

import React from 'react';

if (process.env.NODE_ENV !== 'production') {
  const whyDidYouRender = require('@welldone-software/why-did-you-render/dist/no-classes-transpile/umd/whyDidYouRender.min.js');
  whyDidYouRender(React);
}

Not doing so will result in a bug where a transpiled class tries to extend a native class:

Class constructors must be invoked with 'new'.

Usage

Mark all the components you want to be notified about their re-renders with whyDidYouRender like so:

class BigListPureComponent extends React.PureComponent {
  static whyDidYouRender = true
  render(){
    return (
      //some heavy render you want to ensure doesn't happen if its not neceserry
    )
  }
}

Or like this:

const BigListPureComponent = props => (
  <div>
    //some heavy component you want to ensure doesn't happen if its not neceserry
  </div>
)
BigListPureComponent.whyDidYouRender = true

You can also pass an object to specify more advanced settings:

EnhancedMenu.whyDidYouRender = {
  logOnDifferentValues: true,
  customName: 'EnhancedMenu'
}
  • logOnDifferentValues:

    Normally only re-renders that are caused by equal values in props / state trigger notifications:

    render(<Menu a={1}/>)
    render(<Menu a={1}/>)

    This option will trigger notifications even if they occurred because of different props / state (Thus, because of "legit" re-renders):

    render(<Menu a={1}/>)
    render(<Menu a={2}/>)
  • customName:

    Sometimes the name of the component can be very inconvenient. For example:

    const EnhancedMenu = Connect(withPropsOnChange(withPropsOnChange(withStateHandlers(withPropsOnChange(withState(withPropsOnChange(lifecycle(withPropsOnChange(withPropsOnChange(onlyUpdateForKeys(LoadNamespace(Connect(withState(withState(withPropsOnChange(lifecycle(withPropsOnChange(withHandlers(withHandlers(withHandlers(withHandlers(Connect(lifecycle(Menu))))))))))))))))))))))))

    will have the display name:

    Connect(withPropsOnChange(withPropsOnChange(withStateHandlers(withPropsOnChange(withState(withPropsOnChange(lifecycle(withPropsOnChange(withPropsOnChange(onlyUpdateForKeys(LoadNamespace(Connect(withState(withState(withPropsOnChange(lifecycle(withPropsOnChange(withHandlers(withHandlers(withHandlers(withHandlers(Connect(lifecycle(Menu))))))))))))))))))))))))

    To prevent polluting the console, and any other reason, you can change it using customName.

Options

Optionally you can pass in options as a second parameter. The following options are available:

  • include: [RegExp, ...] (null by default)
  • exclude: [RegExp, ...] (null by default)
  • trackHooks: true
  • logOnDifferentValues: false
  • hotReloadBufferMs: 500
  • onlyLogs: false
  • collapseGroups: false
  • titleColor
  • diffNameColor
  • diffPathColor
  • notifier: ({Component, displayName, prevProps, prevState, nextProps, nextState, reason, options}) => void

include / exclude

You can include or exclude tracking for re-renders for components by their displayName with the include and exclude options.

Notice: exclude takes priority over both include and whyDidYouRender statics on components.

For example, the following code is used to track all redundant re-renders that are caused by React-Redux:

whyDidYouRender(React, { include: [/^ConnectFunction/] });

trackHooks

You can turn off tracking of hooks changes.

Understand and fix hook issues >> HERE <<.

logOnDifferentValues

Normally, you only want notifications about component re-renders when their props and state are the same, because it means these re-renders could of been avoided. But you can also track all re-renders, even on different state/props.

render(<BigListPureComponent a={1}/>)
render(<BigListPureComponent a={2}/>)
// this will only cause whyDidYouRender notifications for {logOnDifferentValues: true}

hotReloadBufferMs

Time in milliseconds to ignore updates after a hot reload is detected.

We can't currently know exactly if a render was triggered by hot reload, so instead, we ignore all updates for hotReloadBufferMs (default: 500) after a hot reload.

onlyLogs

If you don't want to use console.group to group logs by component, you can print them as simple logs.

collapseGroups

Grouped logs can start collapsed:

titleColor / diffNameColor / diffPathColor

Controls the colors used in the console notifications

notifier

You can create a custom notifier if the default one does not suite your needs.

Credit

Inspired by the following previous work:

https://github.com/maicki/why-did-you-update which i had the chance to maintain for some time.

https://github.com/garbles/why-did-you-update where A deep dive into React perf debugging is credited for the idea.

License

This library is MIT licensed.

You can’t perform that action at this time.