why-did-you-render
par Welldone Software Monkey Patches React
pour vous informer des nouveaux rendus potentiellement évitables. (Fonctionne également avec React Native
.)
Par exemple, si vous transmettez style={{width: '100%'}}
à un gros composant pur, il sera toujours restitué à chaque création d'élément :
<BigListPureComponent style={{width: '100%'}}/>
Cela peut également vous aider à suivre simplement quand et pourquoi un certain composant est restitué.
La dernière version de la bibliothèque a été testée (tests unitaires et E2E) avec React@18
uniquement. Pour React 17 et 16, veuillez utiliser la version @^7.
npm install @welldone-software/why-did-you-render --save-dev
ou
yarn add --dev @welldone-software/why-did-you-render
Si vous utilisez la transformation JSX automatic
, définissez la bibliothèque comme source d'importation et assurez-vous que preset-react
est en mode development
.
['@babel/preset-react', { runtime : 'automatic', développement : process.env.NODE_ENV === 'development', importSource : '@welldone-software/why-did-you-render',}]
Malheureusement, le metro-react-native-babel-preset
fourni avec React-Native ne vous permet pas de modifier les options du plugin babel/plugin-transform-react-jsx
. Ajoutez simplement le plugin avec les options répertoriées ci-dessous et démarrez le packager React-Native comme d'habitude. L'environnement par défaut pour Babel est "développement". Si vous n'utilisez pas expo lorsque vous travaillez avec React-Native, la méthode suivante vous aidera.
module.exports = { presets : ['module:metro-react-native-babel-preset'], env : { développement : { plugins : [['@babel/plugin-transform-react-jsx', { runtime : ' classique' }]], }, },}
Vous pouvez transmettre les paramètres à @babel/preset-react
via babel-preset-expo
// babel.config.jsmodule.exports = function (api) { api.cache(true); return { presets : [ [ "babel-preset-expo", { jsxImportSource : "@welldone-software/why-did-you-render", }, ], ], };} ;
Remarque : Create React App (CRA) ^4 utilise la transformation JSX
automatic
. Voir le commentaire suivant sur la façon de réaliser cette étape avec CRA
Créez un fichier wdyr.js
et importez-le lors de la première importation dans votre application.
wdyr.js
:
importer React depuis 'react';if (process.env.NODE_ENV === 'development') { const WhyDidYouRender = require('@welldone-software/why-did-you-render'); pourquoiDidYouRender(React, { trackAllPureComponents : true, });}
Remarque : La bibliothèque ne doit JAMAIS être utilisée en production car elle ralentit React
Dans Typescript, appelez le fichier wdyr.ts et ajoutez la ligne suivante en haut du fichier pour importer les types du package :
/// <reference types="@welldone-software/pourquoi-did-you-render" />
Importez wdyr
comme première importation (même react-hot-loader
):
index.js
:
importer './wdyr'; // <--- first importimport 'react-hot-loader';import {hot} depuis 'react-hot-loader/root';import React depuis 'react';import ReactDOM depuis 'react-dom';// . ..importer {App} depuis './app';// ...const HotApp = hot(App);// ...ReactDOM.render(<HotApp/>, document.getElementById('root'));
Si vous utilisez trackAllPureComponents
comme nous le suggérons, tous les composants purs (React.PureComponent ou React.memo) seront suivis.
Sinon, ajoutez whyDidYouRender = true
aux classes/fonctions de composants que vous souhaitez suivre. (par exemple Component.whyDidYouRender = true
)
Plus d’informations sur ce qui est suivi peuvent être trouvées dans Composants de suivi.
Vous ne voyez aucun journal WDYR ? Consultez la section de dépannage ou recherchez dans les problèmes.
De plus, le suivi des hooks personnalisés est possible en utilisant trackExtraHooks
. Par exemple, si vous souhaitez suivre useSelector
depuis React Redux :
wdyr.js
:
importer React depuis 'react';// Pour réagir natif, vous souhaiterez peut-être utiliser // l'indicateur __DEV__ au lieu de process.env.NODE_ENV === 'development'if (process.env.NODE_ENV === 'development') { const WhyDidYouRender = require('@welldone-software/why-did-you-render'); const ReactRedux = require('react-redux'); pourquoiDidYouRender(React, { trackAllPureComponents : true, trackExtraHooks : [ [ReactRedux, 'useSelector'] ] });}
Notez qu'il existe actuellement un problème avec la réécriture des exportations de fichiers importés dans
webpack
. Une solution de contournement rapide peut vous aider : #85 - trackExtraHooks ne peut pas définir la propriété.
Pourquoi avez-vous rendu le composant Mr. Big Pure React ???
Scénarios de réparation courants pour lesquels cette bibliothèque peut vous aider
React Hooks - Comprendre et résoudre les problèmes de hooks
Pourquoi avez-vous sorti le rendu v4 ! - Prise en charge de TypeScript, suivi des hooks personnalisés (comme useSelector de React-Redux), suivi de tous les composants purs.
Exemple Next.js
React-Redux avec des crochets
Mobx n'est actuellement pas pris en charge
Plugin flipper React-Native créé par @allen-hsu
Vous pouvez tester la bibliothèque dans le bac à sable officiel.
Et un autre bac à sable officiel avec suivi des hooks
Vous pouvez suivre tous les composants purs (React.PureComponent ou React.memo) à l'aide de l'option trackAllPureComponents: true
.
Vous pouvez également suivre manuellement n'importe quel composant de votre choix en définissant whyDidYouRender
dessus comme ceci :
class BigList extends React.Component { static WhyDidYouRender = true render(){ return ( //un rendu lourd dont vous voulez vous assurer qu'il ne se produit pas si ce n'est pas nécessaire) }}
Ou pour les composants fonctionnels :
const BigListPureComponent = props => ( <div> //un composant lourd dont vous voulez vous assurer qu'il ne se produira pas s'il n'est pas nécessaire </div>)BigListPureComponent.whyDidYouRender = true
Vous pouvez également transmettre un objet pour spécifier des paramètres de suivi plus avancés :
EnhancedMenu.whyDidYouRender = {logOnDifferentValues : true, customName : 'Menu'}
logOnDifferentValues
:
Normalement, seuls les rendus provoqués par des valeurs égales dans les notifications de déclenchement d'accessoires/état :
rendre(<Menu a={1}/>)render(<Menu a={1}/>)
Cette option déclenchera des notifications même si elles se sont produites en raison de différents accessoires/états (donc, en raison de re-rendus « légitimes ») :
rendre(<Menu a={1}/>)render(<Menu a={2}/>)
customName
:
Parfois, le nom du composant peut être manquant ou très gênant. Par exemple:
withPropsOnChange(withPropsOnChange(withStateHandlers(withPropsOnChange(withState(withPropsOnChange(lifecycle(withPropsOnChange(withPropsOnChange(onlyUpdateForKeys(LoadNamesp ace(Connect(withState(withState(withPropsOnChange(lifecycle(withPropsOnChange(withHandlers(withHandlers(withHandlers(withHandlers(Connect(lifecycle(Menu))))))))))))))))))))))))
Vous pouvez éventuellement transmettre des options
comme deuxième paramètre. Les options suivantes sont disponibles :
include: [RegExp, ...]
( null
par défaut)
exclude: [RegExp, ...]
( null
par défaut)
trackAllPureComponents: false
trackHooks: true
trackExtraHooks: []
logOwnerReasons: true
logOnDifferentValues: false
hotReloadBufferMs: 500
onlyLogs: false
collapseGroups: false
titleColor
diffNameColor
diffPathColor
notifier: ({Component, displayName, hookName, prevProps, prevState, prevHook, nextProps, nextState, nextHook, reason, options, ownerDataMap}) => void
getAdditionalOwnerData: (element) => {...}
null
) Vous pouvez inclure ou exclure le suivi des composants par leur displayName à l'aide des options include
et exclude
.
Par exemple, le code suivant est utilisé pour suivre tous les rendus redondants provoqués par l'ancien React-Redux :
pourquoiDidYouRender(React, { include : [/^ConnectFunction/] });
Remarque : l'exclusion est prioritaire sur
include
et la définition manuelle dewhyDidYouRender =
false
) Vous pouvez suivre tous les composants purs (composants React.memo
et React.PureComponent
)
Remarque : Vous pouvez exclure le suivi de n'importe quel composant spécifique avec
whyDidYouRender = false
true
)Vous pouvez désactiver le suivi des modifications des hooks.
Comprendre et résoudre les problèmes de hook.
[]
)Suivre les hooks personnalisés :
WhyDidYouRender(React, { trackExtraHooks: [ // remarquez que 'useSelector' est une exportation nommée [ReactRedux, 'useSelector'], ]});
Il y a actuellement un problème avec la réécriture des exportations des fichiers importés dans le webpack. Une solution de contournement est disponible ici : #85 - trackExtraHooks ne peut pas définir la propriété
true
)Une façon de résoudre les problèmes de rendu consiste à empêcher le propriétaire du composant de procéder à un nouveau rendu.
Cette option est true
par défaut et vous permet d'afficher les raisons pour lesquelles un composant propriétaire est restitué.
false
)Normalement, vous souhaitez uniquement des journaux sur les rendus de composants lorsqu'ils auraient pu être évités.
Avec cette option, il est possible de suivre tous les rendus.
Par exemple:
render(<BigListPureComponent a={1}/>)render(<BigListPureComponent a={2}/>)// ne se connectera que si vous utilisez {logOnDifferentValues: true}
500
)Délai en millisecondes pour ignorer les mises à jour après la détection d'un rechargement à chaud.
Lorsqu'un rechargement à chaud est détecté, nous ignorons toutes les mises à jour pour hotReloadBufferMs
afin de ne pas spammer la console.
false
) Si vous ne souhaitez pas utiliser console.group
pour regrouper les journaux, vous pouvez les imprimer sous forme de simples journaux.
false
)Les journaux groupés peuvent être réduits.
'#058'
)'blue'
)'red'
)Contrôle les couleurs utilisées dans les notifications de la console
Vous pouvez créer un notificateur personnalisé si celui par défaut ne répond pas à vos besoins.
undefined
)Vous pouvez fournir une fonction qui collecte des données supplémentaires à partir de l'élément de réaction d'origine. L'objet renvoyé par cette fonction sera ajouté au OwnerDataMap auquel vous pourrez accéder ultérieurement dans le cadre de votre remplacement de fonction de notification.
Si vous êtes en production, WDYR est probablement désactivé.
Peut-être qu'aucun composant n'est suivi
Consultez à nouveau les composants de suivi.
Si vous suivez uniquement les composants purs à l'aide de trackAllPureComponents: true
, vous ne suivrez que l'un ou l'autre (React.PureComponent ou React.memo), peut-être qu'aucun de vos composants n'est pur, donc aucun d'entre eux ne sera suivi.
Peut-être que tu n'as aucun problème
Essayez de provoquer un problème en rendant temporairement l'ensemble de l'application deux fois dans son point d'entrée :
index.js
:
const HotApp = hot(App);HotApp.whyDidYouRender = true;ReactDOM.render(<HotApp/>, document.getElementById('root'));ReactDOM.render(<HotApp/>, document.getElementById('root') );
Il y a actuellement un problème avec la réécriture des exportations de fichiers importés dans webpack
. Une solution de contournement rapide peut vous aider : #85 - trackExtraHooks ne peut pas définir la propriété.
connect
HOC spamme la console Étant donné que connect
pallie les statiques, si vous ajoutez WDYR au composant interne, il est également ajouté au composant HOC où les hooks complexes sont exécutés.
Pour résoudre ce problème, ajoutez le whyDidYouRender = true
static à un composant après la connexion :
const SimpleComponent = ({a}) => <div data-testid="foo">{ab}</div>) // pas avant la connexion : // SimpleComponent.whyDidYouRender = true const ConnectedSimpleComponent = connect( state => ({a: state.a}) )(SimpleComponent) // après la connexion : SimpleComponent.whyDidYouRender = true
Pour voir les sourcesmaps de la bibliothèque, utilisez le source-map-loader.
Inspiré des travaux antérieurs suivants :
github.com/maicki/why-did-you-update (n'est plus public) que j'ai eu la chance de maintenir pendant quelques temps.
https://github.com/garbles/why-did-you-update où une plongée approfondie dans le débogage des performances de React est créditée pour l'idée.
Cette bibliothèque est sous licence MIT.