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
إذا كنت تستخدم تحويل JSX automatic
، فاضبط المكتبة لتكون مصدر الاستيراد، وتأكد من أن preset-react
في وضع development
.
['@babel/preset-react', { runtime: 'automatic', Development:process.env.NODE_ENV === 'development', importSource: '@welldone-software/why-did-you-render',}]
لسوء الحظ، فإن metro-react-native-babel-preset
الذي يأتي مع React-native خارج الصندوق لا يسمح لك بتغيير خيارات المكون الإضافي babel/plugin-transform-react-jsx
. ما عليك سوى إضافة المكوّن الإضافي مع الخيارات الموضحة أدناه وبدء تشغيل برنامج رد الفعل الأصلي كالمعتاد. البيئة الافتراضية لـ babel هي "التنمية". إذا كنت لا تستخدم Expo عند العمل مع React-Native، فستساعدك الطريقة التالية.
Module.exports = { الإعدادات المسبقة: ['module:metro-react-native-babel-preset'], env: { تطوير: { plugins: [['@babel/plugin-transform-react-jsx', { runtime: ' كلاسيكي' }]]، }، }،}
يمكنك تمرير المعلمات إلى @babel/preset-react
من خلال babel-preset-expo
// babel.config.jsmodule.exports = function (api) { api.cache(true); إرجاع { الإعدادات المسبقة: [ [ "babel-preset-expo"، { jsxImportSource: "@welldone-software/why-did-you-render"، }، ]، ]، }؛}؛
ملاحظة: يستخدم إنشاء تطبيق React (CRA) ^4 تحويل JSX
automatic
. راجع التعليق التالي حول كيفية القيام بهذه الخطوة مع CRA
قم بإنشاء ملف wdyr.js
وقم باستيراده كأول عملية استيراد في التطبيق الخاص بك.
wdyr.js
:
import React from 'react';if (process.env.NODE_ENV === 'development') { const WhyDidYouRender = require('@welldone-software/why-did-you-render'); لماذاDidYouRender(React, {trackAllPureComponents: true, });}
ملاحظة: لا ينبغي أبدًا استخدام المكتبة في الإنتاج لأنها تؤدي إلى إبطاء React
في Typescript، قم باستدعاء الملف wdyr.ts وأضف السطر التالي إلى أعلى الملف لاستيراد أنواع الحزمة:
/// <أنواع المرجع = "@welldone-software/why-did-you-render" />
قم باستيراد wdyr
كأول عملية استيراد (حتى قبل react-hot-loader
):
index.js
:
استيراد './wdyr'؛ // <--- أول استيراد 'react-hot-loader';استيراد {hot} من 'react-hot-loader/root';استيراد React من 'react';استيراد ReactDOM من '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
. على سبيل المثال، إذا كنت تريد تتبع useSelector
من React Redux:
wdyr.js
:
import React from 'react';// بالنسبة إلى رد الفعل الأصلي، قد ترغب في استخدام // علامة __DEV__ بدلاً منprocess.env.NODE_ENV === 'development'if (process.env.NODE_ENV === 'development') { const لماذاDidYouRender = require('@welldone-software/why-did-you-render'); const ReactRedux = require('react-redux'); لماذاDidYouRender(React, {trackAllPureComponents: true,trackExtraHooks: [ [[ReactRedux, 'useSelector'] ] });}
لاحظ أن هناك حاليًا مشكلة في إعادة كتابة عمليات تصدير الملفات المستوردة في
webpack
. يمكن أن يساعد الحل السريع في حل هذه المشكلة: #85 - لا يمكن لـtrackExtraHooks تعيين الخاصية.
لماذا قمت بتقديم مكون السيد Big Pure React ؟؟؟
سيناريوهات الإصلاح الشائعة التي يمكن لهذه المكتبة المساعدة فيها
React Hooks - فهم مشكلات الخطافات وإصلاحها
لماذا قمت بإصدار الإصدار الرابع! - دعم TypeScript، وتتبع الخطافات المخصصة (مثل useSelector الخاص بـ React-Redux)، وتتبع جميع المكونات النقية.
مثال Next.js
رد فعل الإعادة مع الخطافات
Mobx غير مدعوم حاليًا
React-Native flipper البرنامج المساعد الذي صممه @allen-hsu
يمكنك اختبار المكتبة في وضع الحماية الرسمي.
وصندوق رمل رسمي آخر مع تتبع الخطافات
يمكنك تتبع جميع المكونات النقية (React.PureComponent أو React.memo) باستخدام خيار trackAllPureComponents: true
.
يمكنك أيضًا تتبع أي مكون تريده يدويًا عن طريق تعيين whyDidYouRender
عليهم مثل هذا:
class BigList يمتد React.Component { static WhyDidYouRender = true render(){ return ( // بعض عمليات العرض الثقيلة التي تريد التأكد من عدم حدوثها إذا لم تكن ضرورية ) }}
أو للمكونات الوظيفية:
const BigListPureComponent =props => ( <div> // بعض المكونات الثقيلة التي تريد التأكد من عدم حدوثها إذا لم تكن ضرورية </div>)BigListPureComponent.whyDidYouRender = true
يمكنك أيضًا تمرير كائن لتحديد إعدادات تتبع أكثر تقدمًا:
EnhancedMenu.whyDidYouRender = { logOnDifferentValues: true، customName: 'Menu'}
logOnDifferentValues
:
عادةً، يتم فقط عمليات إعادة العرض التي تنتج عن قيم متساوية في الخاصيات/الحالة التي تؤدي إلى تشغيل الإشعارات:
تقديم(<القائمة أ={1}/>)تقديم(<القائمة أ={1}/>)
سيؤدي هذا الخيار إلى تشغيل الإشعارات حتى لو حدثت بسبب اختلاف الدعائم/الحالات (وبالتالي، بسبب عمليات إعادة العرض "الشرعية"):
تقديم(<القائمة أ={1}/>)تقديم(<القائمة أ={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 الأقدم:
لماذاDidYouRender(React, { include: [/^ConnectFunction/] });
ملاحظة: الاستبعاد له الأولوية على كل من
include
والتعيين يدويًاwhyDidYouRender =
false
) يمكنك تتبع جميع المكونات النقية (كل من مكونات React.memo
و React.PureComponent
)
إشعار: يمكنك استبعاد تتبع أي مكون محدد باستخدام
whyDidYouRender = false
true
)يمكنك إيقاف تشغيل تتبع تغييرات الخطافات.
فهم مشكلات الخطاف وإصلاحها.
[]
)تتبع الخطافات المخصصة:
لماذاDidYouRender(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
static إلى أحد المكونات بعد الاتصال:
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 perf إلى هذه الفكرة.
هذه المكتبة مرخصة من معهد ماساتشوستس للتكنولوجيا.