why-did-you-render
от Welldone Software — обезьяньи патчи React
которые уведомляют вас о потенциально предотвратимых повторных рендерингах. (Также работает с React Native
.)
Например, если вы передадите style={{width: '100%'}}
большому чистому компоненту, он всегда будет перерисовываться при каждом создании элемента:
<BigListPureComponent style={{width: '100%'}}/>
Это также может помочь вам просто отслеживать, когда и почему определенный компонент перерисовывается.
Последняя версия библиотеки была протестирована (модульные тесты и E2E) только с React@18
. Для 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',}]
К сожалению, metro-react-native-babel-preset
, поставляемая вместе с React-native, не позволяет вам изменять параметры плагина babel/plugin-transform-react-jsx
. Просто добавьте плагин с параметрами, указанными ниже, и запустите упаковщик React Native, как обычно. Окружающая среда по умолчанию для Babel — «разработка». Если вы не используете expo при работе с React-native, вам поможет следующий метод.
module.exports = { пресеты: ['module:metro-react-native-babel-preset'], env: { development: { плагины: [['@babel/plugin-transform-react-jsx', { runtime: ' классика' }]], }, },}
Вы можете передать параметры @babel/preset-react
через babel-preset-expo
//babel.config.jsmodule.exports = function (api) { api.cache(true); return { пресеты: [ [ "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') { constWhyDidYouRender = require('@welldone-software/why-did-you-render'); WhyDidYouRender(React, { trackAllPureComponents: true, });}
Примечание. Библиотеку НИКОГДА нельзя использовать в производстве, поскольку она замедляет React.
В Typescript вызовите файл wdyr.ts и добавьте следующую строку в начало файла, чтобы импортировать типы пакета:
/// <reference type="@welldone-software/why-did-you-render" />
Импортируйте wdyr
в качестве первого импорта (даже до react-hot-loader
):
index.js
:
импортировать './wdyr'; // <--- first importimport 'react-hot-loader';import {hot} из 'react-hot-loader/root';импортировать React из 'react';импортировать ReactDOM из 'react-dom';// . ..import {App} из './app';// ...const HotApp = hot(App);// ...ReactDOM.render(<HotApp/>, document.getElementById('root'));
Если вы используете trackAllPureComponents
, как мы предлагаем, все чистые компоненты (React.PureComponent или React.memo) будут отслеживаться.
В противном случае добавьтеWhyDidYouRender whyDidYouRender = true
к классам/функциям компонентов, которые вы хотите отслеживать. (например Component.whyDidYouRender = true
)
Дополнительную информацию о том, что отслеживается, можно найти в разделе «Компоненты отслеживания».
Не видите журналы WDYR? Посетите раздел устранения неполадок или выполните поиск по проблемам.
Кроме того, отслеживание пользовательских перехватчиков возможно с помощью trackExtraHooks
. Например, если вы хотите отслеживать useSelector
из React Redux:
wdyr.js
:
импортировать React из 'react';// Для реагирования вы можете использовать // флаг __DEV__ вместо Process.env.NODE_ENV === 'development'if (process.env.NODE_ENV === 'development') { constWhyDidYouRender = require('@welldone-software/why-did-you-render'); const ReactRedux = require('реагировать-редукс'); WhyDidYouRender(React, { trackAllPureComponents: true, trackExtraHooks: [[ReactRedux, 'useSelector']] });}
Обратите внимание, что в настоящее время существует проблема с перезаписью экспорта импортированных файлов в
webpack
. В этом может помочь быстрый обходной путь: #85 — trackExtraHooks не может установить свойство.
Почему вы визуализировали компонент Mr. Big Pure React???
Распространенные сценарии исправления, с которыми может помочь эта библиотека
React Hooks — понимание и устранение проблем с крючками
Почему вы выпустили Render v4! — Поддержка TypeScript, отслеживание пользовательских перехватчиков (например, useSelector в React-Redux), отслеживание всех чистых компонентов.
Пример Next.js
React-Redux с хуками
Mobx в настоящее время не поддерживается.
Плагин флиппера React-Native, созданный @allen-hsu
Вы можете протестировать библиотеку в официальной песочнице.
И еще официальная песочница с отслеживанием хуков
Вы можете отслеживать все чистые компоненты (React.PureComponent или React.memo), используя параметр trackAllPureComponents: true
.
Вы также можете вручную отслеживать любой компонент, установив для whyDidYouRender
следующим образом:
class BigList расширяет React.Component { staticWhyDidYouRender = true render(){ return ( //некоторый тяжелый рендеринг, который вы хотите гарантировать, не произойдет, если в этом нет необходимости) }}
Или для функциональных компонентов:
const BigListPureComponent = props => ( <div> //какой-то тяжелый компонент, который вы хотите гарантировать, не произойдет, если в этом нет необходимости </div>)BigListPureComponent.whyDidYouRender = true
Вы также можете передать объект, чтобы указать более расширенные настройки отслеживания:
EnhancedMenu.whyDidYouRender = {logOnDifferentValues: true, customName: 'Меню'}
logOnDifferentValues
:
Обычно перерисовываются только те события, которые вызваны равными значениями в уведомлениях о срабатывании реквизита/состояния:
render(<Menu a={1}/>)render(<Menu a={1}/>)
Эта опция будет вызывать уведомления, даже если они произошли из-за разных реквизитов/состояний (таким образом, из-за «законных» повторных рендерингов):
render(<Menu a={1}/>)render(<Menu a={2}/>)
customName
:
Иногда название компонента может отсутствовать или быть очень неудобным. Например:
withPropsOnChange(withPropsOnChange(withStateHandlers(withPropsOnChange(withState(withPropsOnChange(жизненный цикл(withPropsOnChange(withPropsOnChange(onlyUpdateForKeys(LoadNamesp)) ace(Connect(withState(withState(withPropsOnChange(жизненный цикл(withPropsOnChange(withHandlers(withHandlers(withHandlers(withHandlers(Connect(жизненный цикл(Меню)))))))))))))))))))))))))
При желании вы можете передать 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
и установкой вручнуюWhyDidYouRenderwhyDidYouRender =
false
) Вы можете отслеживать все чистые компоненты (компоненты React.memo
и React.PureComponent
).
Примечание. Вы можете исключить отслеживание любого конкретного компонента,
whyDidYouRender = false
true
)Вы можете отключить отслеживание изменений хуков.
Поймите и устраните проблемы с крючками.
[]
)Отслеживайте пользовательские хуки:
WhyDidYouRender(React, { trackExtraHooks: [ // обратите внимание, что 'useSelector' — это именованный экспорт [ReactRedux, 'useSelector'], ]});
В настоящее время существует проблема с перезаписью экспорта импортированных файлов в веб-пакете. Обходной путь доступен здесь: #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
Чтобы просмотреть исходные карты библиотеки, используйте source-map-loader.
Вдохновлен следующей предыдущей работой:
github.com/maicki/why-did-you-update (больше не является общедоступным), который у меня была возможность поддерживать в течение некоторого времени.
https://github.com/garbles/why-did-you-update, где за идею приписывается глубокое погружение в отладку производительности React.
Эта библиотека имеет лицензию MIT.