why-did-you-render
由 Welldone Software 猴子补丁React
以通知您可能可以避免的重新渲染。 (也适用于React Native
。)
例如,如果您将style={{width: '100%'}}
传递给一个大的纯组件,它总是会在每个元素创建时重新渲染:
<BigListPureComponent style={{width: '100%'}}/>
它还可以帮助您简单地跟踪某个组件重新渲染的时间和原因。
该库的最新版本仅使用React@18
进行了测试(单元测试和 E2E)。对于 React 17 和 16,请使用版本@^7。
npm install @welldone-software/why-did-you-render --save-dev
或者
yarn add --dev @welldone-software/why-did-you-render
如果您使用automatic
JSX转换,请将库设置为导入源,并确保preset-react
处于development
模式。
['@babel/preset-react', { 运行时: '自动', 开发: process.env.NODE_ENV === '开发', importSource: '@welldone-software/why-did-you-render',}]
不幸的是,react-native 开箱即用的metro-react-native-babel-preset
不允许您更改babel/plugin-transform-react-jsx
插件的选项。只需添加带有下面列出的选项的插件,然后像往常一样启动react-native packager。 babel 的默认环境是“development”。如果您在使用react-native时不使用expo,以下方法将对您有所帮助。
module.exports = { 预设:['模块:metro-react-native-babel-preset'],env:{ 开发:{ 插件:[['@babel/plugin-transform-react-jsx',{ 运行时:'经典的' }]], }, },}
您可以通过babel-preset-expo
将参数传递给@babel/preset-react
// babel.config.jsmodule.exports = function (api) { api.cache(true); 返回 { 预设:[ [ "babel-preset-expo", { jsxImportSource: "@welldone-software/why-did-you-render", }, ], ], };};
注意:Create React App (CRA) ^4确实使用了
automatic
JSX 转换。请参阅以下有关如何使用 CRA 执行此步骤的评论
创建wdyr.js
文件并将其作为应用程序中的第一个导入导入。
wdyr.js
:
import React from 'react';if (process.env.NODE_ENV === 'development') { const WhyDidYouRender = require('@welldone-software/why-did-you-render'); WhyDidYouRender(React, { trackAllPureComponents: true, });}
注意:该库不应该在生产中使用,因为它会减慢 React 的速度
在 Typescript 中,调用文件 wdyr.ts 并将以下行添加到文件顶部以导入包的类型:
/// <reference types="@welldone-software/why-did-you-render" />
将wdyr
作为第一次导入导入(甚至在react-hot-loader
之前):
index.js
:
导入'./wdyr'; // <--- 首先 importimport 'react-hot-loader';import {hot} from 'react-hot-loader/root';import React from 'react';import ReactDOM from 'react-dom';// . ..import {App} from './app';// ...const HotApp = hot(App);// ...ReactDOM.render(<HotApp/>, document.getElementById('root'));
如果您像我们建议的那样使用trackAllPureComponents
,则将跟踪所有纯组件(React.PureComponent 或 React.memo)。
否则,将whyDidYouRender = true
添加到要跟踪的组件类/函数中。 (fe Component.whyDidYouRender = true
)
有关跟踪内容的更多信息可以在跟踪组件中找到。
看不到任何 WDYR 日志?查看故障排除部分或搜索问题。
此外,还可以使用trackExtraHooks
来跟踪自定义挂钩。例如,如果您想跟踪 React Redux 中的useSelector
:
wdyr.js
:
import React from 'react';// 对于react-native,您可能需要使用 // __DEV__ 标志而不是 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'); WhyDidYouRender(React, { trackAllPureComponents: true, trackExtraHooks: [ [ReactRedux, 'useSelector'] ] });}
请注意,当前在
webpack
中重写导入文件的导出存在问题。一个快速的解决方法可以帮助解决这个问题:#85 - trackExtraHooks 无法设置属性。
你为什么要渲染 Mr. Big Pure React 组件???
该库可以帮助解决常见的修复场景
React Hooks - 了解并修复 Hooks 问题
为什么发布了 Render v4! - TypeScript 支持、自定义钩子跟踪(如 React-Redux 的 useSelector)、跟踪所有纯组件。
Next.js 示例
带 Hook 的 React-Redux
目前不支持 Mobx
由 @allen-hsu 制作的 React-Native Flipper 插件
您可以在官方沙箱中测试该库。
另一个带有钩子跟踪的官方沙箱
您可以使用trackAllPureComponents: true
选项跟踪所有纯组件(React.PureComponent 或 React.memo)。
您还可以通过设置whyDidYouRender
来手动跟踪任何您想要的组件,如下所示:
class BigList extends React.Component { static WhyDidYouRender = true render(){ return ( //如果不需要的话,你想确保不会发生一些繁重的渲染 ) }}
或者对于功能组件:
const BigListPureComponent = props => ( <div> //您希望确保不必要的某些重组件不会发生 </div>)BigListPureComponent.whyDidYouRender = true
您还可以传递一个对象来指定更高级的跟踪设置:
EnhancedMenu.whyDidYouRender = { logOnDifferentValues: true, customName: '菜单'}
logOnDifferentValues
:
通常,只有由 props / state 触发通知中的相同值引起的重新渲染:
渲染(<Menu a={1}/>)渲染(<Menu a={1}/>)
即使由于不同的道具/状态而发生通知,此选项也会触发通知(因此,由于“合法”重新渲染):
渲染(<Menu a={1}/>)渲染(<Menu a={2}/>)
customName
:
有时组件的名称可能会丢失或非常不方便。例如:
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))))))))))))))))))))))))))
您可以选择传入options
作为第二个参数。可以使用以下选项:
include: [RegExp, ...]
(默认为null
)
exclude: [RegExp, ...]
(默认为null
)
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
)您可以使用include
和exclude
选项按组件的显示名称包含或排除对组件的跟踪。
例如,以下代码用于跟踪由较旧的 React-Redux 引起的所有冗余重新渲染:
WhyDidYouRender(React, { include: [/^ConnectFunction/] });
注意:排除优先于
include
和手动设置whyDidYouRender =
false
)您可以跟踪所有纯组件( React.memo
和React.PureComponent
组件)
注意:您可以使用
whyDidYouRender = false
排除对任何特定组件的跟踪
true
)您可以关闭对挂钩更改的跟踪。
了解并修复钩子问题。
[]
)跟踪自定义挂钩:
WhyDidYouRender(React, { trackExtraHooks: [ // 注意 'useSelector' 是一个命名导出 [ReactRedux, 'useSelector'], ]});
目前在 webpack 中重写导入文件的导出存在问题。此处提供了解决方法:#85 - trackExtraHooks 无法设置属性
true
)解决重新渲染问题的一种方法是阻止组件所有者重新渲染。
该选项默认为true
,它允许您查看所有者组件重新渲染的原因。
false
)通常,您只需要有关组件重新渲染的日志(当组件重新渲染可以避免时)。
使用此选项,可以跟踪所有重新渲染。
例如:
render(<BigListPureComponent a={1}/>)render(<BigListPureComponent a={2}/>)// 仅当您使用 {logOnDifferentValues: true} 时才会记录
500
)检测到热重载后忽略更新的时间(以毫秒为单位)。
当检测到热重载时,我们会忽略hotReloadBufferMs
的所有更新,以免向控制台发送垃圾邮件。
false
)如果您不想使用console.group
对日志进行分组,您可以将它们打印为简单日志。
false
)分组的日志可以折叠。
'#058'
)'blue'
)'red'
)控制控制台通知中使用的颜色
如果默认通知程序不能满足您的需求,您可以创建自定义通知程序。
undefined
)您可以提供一个从原始反应元素中获取附加数据的函数。从此函数返回的对象将被添加到 OwnerDataMap 中,稍后可以在通知程序函数重写中访问该对象。
如果您在生产环境中,WDYR 可能被禁用。
可能没有跟踪任何组件
再次查看跟踪组件。
如果您仅使用trackAllPureComponents: true
跟踪纯组件,那么您将仅跟踪(React.PureComponent 或 React.memo),也许您的组件都不是纯组件,因此它们都不会被跟踪。
也许你没有问题
尝试通过在入口点临时渲染整个应用程序两次来引发问题:
index.js
:
const HotApp = hot(App);HotApp.whyDidYouRender = true;ReactDOM.render(<HotApp/>, document.getElementById('root'));ReactDOM.render(<HotApp/>, document.getElementById('root') );
目前在webpack
中重写导入文件的导出存在问题。一个快速的解决方法可以帮助解决这个问题:#85 - trackExtraHooks 无法设置属性。
connect
HOC 正在向控制台发送垃圾邮件由于connect
葫芦静态,如果将 WDYR 添加到内部组件,它也会添加到运行复杂钩子的 HOC 组件。
要解决此问题,请在连接后将whyDidYouRender = true
静态添加到组件中:
const SimpleComponent = ({a}) => <div data-testid="foo">{ab}</div>) // 不在连接之前: // SimpleComponent.whyDidYouRender = true const ConnectedSimpleComponent = connect( state => ({a: state.a}) )(SimpleComponent) // 连接后:SimpleComponent.whyDidYouRender = true
要查看库的源映射,请使用源映射加载器。
受到以下先前工作的启发:
github.com/maicki/why-did-you-update(不再公开),我有机会维护它一段时间。
https://github.com/garbles/why-did-you-update 这个想法归功于对 React 性能调试的深入研究。
该库已获得麻省理工学院许可。