مكونات التفاعل الفعال: دليل لتحسين أداء التفاعل
نشرت: 2022-03-11منذ تقديمها ، غيّرت React الطريقة التي يفكر بها مطورو الواجهة الأمامية في بناء تطبيقات الويب. مع DOM الظاهري ، تجعل React تحديثات واجهة المستخدم فعالة بقدر ما يمكن أن تكون ، مما يجعل تطبيق الويب الخاص بك أكثر سلاسة. ولكن ، لماذا لا يزال أداء تطبيقات الويب React ذات الحجم المتوسط ضعيفًا؟
حسنًا ، الدليل يكمن في كيفية استخدامك لـ React.
مكتبة حديثة للواجهة الأمامية مثل React لا تجعل تطبيقك أسرع بطريقة سحرية. يتطلب من المطور فهم كيفية عمل React وكيف تعيش المكونات خلال المراحل المختلفة لدورة حياة المكون.
باستخدام React ، يمكنك الحصول على الكثير من تحسينات الأداء التي يجب أن تقدمها عن طريق قياس وتحسين كيف ومتى يتم عرض مكوناتك. وتوفر React فقط الأدوات والوظائف الضرورية لتسهيل ذلك.
في هذا البرنامج التعليمي لـ React ، ستتعلم كيف يمكنك قياس أداء مكونات React وتحسينها لبناء تطبيق ويب React أكثر كفاءة. سوف تتعلم أيضًا كيف تساعد بعض أفضل ممارسات JavaScript أيضًا في جعل تطبيق الويب React الخاص بك يوفر تجربة مستخدم أكثر طلاقة.
كيف تعمل React؟
قبل الغوص في تقنيات التحسين ، نحتاج إلى فهم أفضل لكيفية عمل React.
في جوهر تطوير React ، لديك بنية JSX البسيطة والواضحة ، وقدرة React على بناء ومقارنة DOMs افتراضية. أثرت React منذ إصدارها على العديد من مكتبات الواجهة الأمامية الأخرى. تعتمد المكتبات مثل Vue.js أيضًا على فكرة DOMs الافتراضية.
إليك كيفية عمل React:
يبدأ كل تطبيق من تطبيقات React بمكوِّن جذر ، ويتكون من العديد من المكونات في تشكيل الشجرة. المكوّنات في React هي "وظائف" تعرض واجهة المستخدم بناءً على البيانات (الدعائم والحالة) التي تتلقاها.
يمكننا ترميز هذا كـ F
UI = F(data)
يتفاعل المستخدمون مع واجهة المستخدم ويتسببون في تغيير البيانات. سواء كان التفاعل يتضمن النقر فوق زر ، أو النقر على صورة ، أو سحب عناصر القائمة حولها ، أو طلب AJAX استدعاء واجهات برمجة التطبيقات ، وما إلى ذلك ، فإن كل هذه التفاعلات تغير البيانات فقط. لا يتسببون أبدًا في تغيير واجهة المستخدم بشكل مباشر.
هنا ، البيانات هي كل ما يحدد حالة تطبيق الويب ، وليس فقط ما قمت بتخزينه في قاعدة البيانات الخاصة بك. حتى البتات من حالات الواجهة الأمامية (على سبيل المثال ، أي علامة تبويب محددة حاليًا أو ما إذا كان مربع الاختيار محددًا حاليًا) هي جزء من هذه البيانات.
عندما يكون هناك تغيير في هذه البيانات ، تستخدم React وظائف المكوِّنات لإعادة تصيير واجهة المستخدم ، ولكن افتراضيًا فقط:
UI1 = F(data1) UI2 = F(data2)
يحسب React الاختلافات بين واجهة المستخدم الحالية وواجهة المستخدم الجديدة من خلال تطبيق خوارزمية مقارنة على نسختين من DOM الظاهري.
Changes = Diff(UI1, UI2)
يواصل React بعد ذلك تطبيق تغييرات واجهة المستخدم فقط على واجهة المستخدم الحقيقية على المتصفح.
عندما تتغير البيانات المرتبطة بتغير مكون ، تحدد React ما إذا كان تحديث DOM الفعلي مطلوبًا. يسمح هذا لـ React بتجنب عمليات التلاعب في DOM التي يُحتمل أن تكون باهظة الثمن في المتصفح ، مثل إنشاء عُقد DOM والوصول إلى العقد الموجودة خارج الضرورة.
يمكن أن يكون هذا الاختلاف والعرض المتكرر للمكونات أحد المصادر الأساسية لمشكلات أداء React في أي تطبيق React. يمكن أن يؤدي إنشاء تطبيق React حيث تفشل خوارزمية التباين في التوفيق بشكل فعال ، مما يؤدي إلى عرض التطبيق بالكامل بشكل متكرر إلى تجربة بطيئة بشكل محبط.
من أين تبدأ التحسين؟
ولكن ما هو بالضبط الذي نقوم بتحسينه؟
كما ترى ، أثناء عملية التصيير الأولية ، تبني React شجرة DOM مثل هذا:
بالنظر إلى جزء من التغييرات في البيانات ، ما نريد أن تفعله React هو إعادة تصيير المكونات التي تتأثر مباشرة بالتغيير فقط (وربما تخطي حتى عملية الفرق لبقية المكونات):
ومع ذلك ، فإن ما تقوم به React هو:
في الصورة أعلاه ، يتم عرض جميع العقد الصفراء وتباينها ، مما يؤدي إلى إهدار الوقت / موارد الحساب. هذا هو المكان الذي سنضع فيه جهود التحسين في المقام الأول. تكوين كل مكون لفرز العرض فقط عند الضرورة سيسمح لنا باستعادة دورات وحدة المعالجة المركزية الضائعة هذه.
أخذ مطورو مكتبة React هذا في الاعتبار وقدموا لنا وسيلة ربط لفعل ذلك بالضبط: وظيفة تتيح لنا إخبار React عندما يكون من المناسب تخطي تصيير أحد المكونات.
القياس أولا
كما يصفها روب بايك بأناقة إلى حد ما كواحدة من قواعد البرمجة الخاصة به:
قياس. لا تضبط السرعة حتى تقوم بالقياس ، وحتى ذلك الحين لا تفعل ذلك إلا إذا كان جزء واحد من الكود يثقل كاهل الباقي.
لا تبدأ في تحسين التعليمات البرمجية التي تشعر أنها قد تؤدي إلى إبطاء تطبيقك. بدلاً من ذلك ، دع أدوات قياس أداء React ترشدك خلال الطريق.
لدى React أداة قوية لهذا الغرض فقط. باستخدام مكتبة react-addons-perf
يمكنك الحصول على نظرة عامة على الأداء العام لتطبيقك.
الاستخدام بسيط للغاية:
Import Perf from 'react-addons-perf' Perf.start(); // use the app Perf.stop(); Perf.printWasted();
سيؤدي هذا إلى طباعة جدول مع مقدار الوقت الضائع للمكونات في العرض.
توفر المكتبة وظائف أخرى تتيح لك طباعة جوانب مختلفة من الوقت الضائع بشكل منفصل (على سبيل المثال ، استخدام printInclusive()
أو printExclusive()
) ، أو حتى طباعة عمليات معالجة DOM (باستخدام وظيفة printOperations()
).
أخذ المقارنة المعيارية خطوة أخرى
إذا كنت شخصًا مرئيًا ، فإن react-perf-tool
هي فقط الشيء الذي تحتاجه.
تعتمد react-perf-tool
رد فعل الأداء على مكتبة react-addons-perf
. يمنحك طريقة مرئية أكثر لتصحيح أداء تطبيق React الخاص بك. يستخدم المكتبة الأساسية للحصول على قياسات ثم تصورها على هيئة رسوم بيانية.
في كثير من الأحيان ، تعد هذه طريقة أكثر ملاءمة لاكتشاف الاختناقات. يمكنك استخدامه بسهولة عن طريق إضافته كمكون لتطبيقك.
هل يجب أن يتفاعل تحديث المكون؟
بشكل افتراضي ، سيتم تشغيل React ، وعرض DOM الظاهري ، ومقارنة الفرق لكل مكون في الشجرة لأي تغيير في الخاصيات أو الحالة. لكن من الواضح أن هذا غير معقول.
مع نمو تطبيقك ، ستؤدي محاولة إعادة عرض ومقارنة DOM الافتراضي بالكامل في كل إجراء إلى إبطاء في النهاية.
توفر React طريقة بسيطة للمطور للإشارة إلى ما إذا كان المكون يحتاج إلى إعادة تصيير. هذا هو المكان الذي يتم فيه تشغيل طريقة shouldComponentUpdate
.
function shouldComponentUpdate(nextProps, nextState) { return true; }
عندما ترجع هذه الوظيفة إلى القيمة "true" لأي مكون ، فإنها تسمح بتشغيل عملية توزيع الفرق.
يمنحك هذا طريقة بسيطة للتحكم في عملية فرق العرض. كلما احتجت إلى منع إعادة تصيير أحد المكونات على الإطلاق ، قم ببساطة بإرجاع false
من الوظيفة. داخل الوظيفة ، يمكنك مقارنة مجموعة الدعائم الحالية والتالية والحالة لتحديد ما إذا كانت إعادة التصيير ضرورية أم لا:
function shouldComponentUpdate(nextProps, nextState) { return nextProps.id !== this.props.id; }
باستخدام React. PureComponent
لتسهيل تقنية التحسين هذه وأتمتتها قليلاً ، توفر React ما يُعرف بالمكوِّن "النقي". إن React.PureComponent
هو تمامًا مثل React.Component
الذي ينفذ shouldComponentUpdate()
مع مقارنة سطحية للدعم والحالة.

React.PureComponent
يكافئ إلى حد ما هذا:
class MyComponent extends React.Component { shouldComponentUpdate(nextProps, nextState) { return shallowCompare(this.props, nextProps) && shallowCompare(this.state, nextState); } … }
نظرًا لأنها تؤدي فقط مقارنة ضحلة ، فقد تجدها مفيدة فقط عندما:
- الدعائم أو الحالات الخاصة بك تحتوي على بيانات بدائية.
- تحتوي الخاصيات والحالات على بيانات معقدة ، لكنك تعرف متى تستدعي
forceUpdate()
لتحديث المكون الخاص بك.
جعل البيانات غير قابلة للتغيير
ماذا لو كان بإمكانك استخدام React.PureComponent
ولكن لا يزال لديك طريقة فعالة لمعرفة متى تغيرت أي دعائم أو حالات معقدة تلقائيًا؟ هذا هو المكان الذي تجعل فيه هياكل البيانات غير القابلة للتغيير الحياة أسهل.
الفكرة وراء استخدام هياكل البيانات غير القابلة للتغيير بسيطة. عندما يتغير كائن يحتوي على بيانات معقدة ، بدلاً من إجراء التغييرات في هذا الكائن ، قم بإنشاء نسخة من هذا الكائن مع التغييرات. هذا يجعل اكتشاف التغييرات في البيانات بسيطًا مثل مقارنة مرجع الكائنين.
يمكنك استخدام Object.assign
أو _.extend
(من Underscore.js أو Lodash):
const newValue2 = Object.assign({}, oldValue); const newValue2 = _.extend({}, oldValue);
والأفضل من ذلك ، يمكنك استخدام مكتبة توفر هياكل بيانات غير قابلة للتغيير:
var map1 = Immutable.Map({a:1, b:2, c:3}); var map2 = map1.set('b', 2); assert(map1.equals(map2) === true); var map3 = map1.set('b', 50); assert(map1.equals(map3) === false);
هنا ، يتم توفير Immutable.Map
بواسطة مكتبة Immutable.js.
في كل مرة يتم فيها تحديث الخريطة set
أساليبها ، يتم إرجاع خريطة جديدة فقط إذا غيرت العملية المحددة القيمة الأساسية. خلاف ذلك ، يتم إرجاع نفس الخريطة.
يمكنك معرفة المزيد حول استخدام هياكل البيانات غير القابلة للتغيير هنا.
المزيد من تقنيات تحسين التطبيقات المتفاعلة
استخدام بناء الإنتاج
عند تطوير تطبيق React ، يتم تقديم تحذيرات ورسائل خطأ مفيدة حقًا. هذه تجعل التعرف على الأخطاء والمشكلات أثناء التطوير نعمة. لكنها تأتي على حساب الأداء.
إذا نظرت إلى الكود المصدري لـ React ، فسترى الكثير من عمليات التحقق من if (process.env.NODE_ENV != 'production')
. هذه الأجزاء من التعليمات البرمجية التي يقوم React بتشغيلها في بيئة التطوير الخاصة بك ليست شيئًا يحتاجه المستخدم النهائي. بالنسبة لبيئات الإنتاج ، يمكن تجاهل كل هذه التعليمات البرمجية غير الضرورية.
إذا قمت بتشغيل مشروعك باستخدام create-react-app
، فيمكنك ببساطة تشغيل npm run build
لإنتاج بنية الإنتاج بدون هذا الرمز الإضافي. إذا كنت تستخدم Webpack مباشرة ، فيمكنك تشغيل webpack -p
(وهو ما يعادل webpack --optimize-minimize --define process.env.NODE_ENV="'production'"
.
وظائف الربط في وقت مبكر
من الشائع جدًا أن ترى الدوال مرتبطة بسياق المكون داخل دالة التصيير. هذا هو الحال غالبًا عندما نستخدم هذه الوظائف للتعامل مع أحداث المكونات الفرعية.
// Creates a new `handleUpload` function during each render() <TopBar onUpload={this.handleUpload.bind(this)} /> // ...as do inlined arrow functions <TopBar onUpload={files => this.handleUpload(files)} />
سيؤدي هذا إلى قيام وظيفة render()
بإنشاء وظيفة جديدة في كل عملية تصيير. أفضل طريقة لفعل الشيء نفسه هي:
class App extends React.Component { constructor(props) { super(props); this.handleUpload = this.handleUpload.bind(this); } render() { … <TopBar onUpload={this.handleUpload} /> … } }
استخدام ملفات متعددة الأجزاء
بالنسبة لتطبيقات الويب أحادية الصفحة React ، غالبًا ما ينتهي بنا المطاف بتجميع كل كود JavaScript للواجهة الأمامية في ملف واحد مصغر. يعمل هذا بشكل جيد مع تطبيقات الويب الصغيرة إلى المتوسطة الحجم. ولكن مع بدء نمو التطبيق ، يمكن أن يصبح تسليم ملف JavaScript المجمع هذا إلى المتصفح بحد ذاته عملية تستغرق وقتًا طويلاً.
إذا كنت تستخدم Webpack لبناء تطبيق React الخاص بك ، فيمكنك الاستفادة من إمكانيات تقسيم الشفرة الخاصة به لفصل كود التطبيق المدمج إلى "أجزاء" متعددة وتسليمها إلى المتصفح حسب الحاجة.
هناك نوعان من التقسيم: تقسيم الموارد وتقسيم الكود عند الطلب.
من خلال تقسيم الموارد ، يمكنك تقسيم محتوى المورد إلى ملفات متعددة. على سبيل المثال ، باستخدام CommonsChunkPlugin ، يمكنك استخراج التعليمات البرمجية الشائعة (مثل جميع المكتبات الخارجية) في ملف "مقطع" خاص به. باستخدام ExtractTextWebpackPlugin ، يمكنك استخراج كل تعليمات CSS البرمجية في ملف CSS منفصل.
سيساعد هذا النوع من التقسيم بطريقتين. يساعد المتصفح على تخزين تلك الموارد التي تتغير بشكل أقل تكرارًا. كما أنه سيساعد المتصفح على الاستفادة من التنزيل المتوازي لتقليل وقت التحميل على الأرجح.
الميزة الأكثر بروزًا في Webpack هي تقسيم الكود عند الطلب. يمكنك استخدامه لتقسيم التعليمات البرمجية إلى جزء يمكن تحميله عند الطلب. يمكن أن يؤدي ذلك إلى الحفاظ على حجم التنزيل الأولي صغيرًا ، مما يقلل الوقت المستغرق لتحميل التطبيق. يمكن للمتصفح بعد ذلك تنزيل أجزاء أخرى من التعليمات البرمجية عند الطلب عندما يحتاجها التطبيق.
يمكنك معرفة المزيد حول تقسيم كود Webpack هنا.
تمكين Gzip على خادم الويب الخاص بك
عادةً ما تكون حزمة JS الخاصة بتطبيق React كبيرة جدًا ، لذلك لجعل صفحة الويب يتم تحميلها بشكل أسرع ، يمكننا تمكين Gzip على خادم الويب (Apache و Nginx وما إلى ذلك)
جميع المتصفحات الحديثة تدعم وتتفاوض تلقائيًا مع ضغط Gzip لطلبات HTTP. يمكن أن يؤدي تمكين ضغط Gzip إلى تقليل حجم الاستجابة المنقولة بنسبة تصل إلى 90٪ ، مما يمكن أن يقلل بشكل كبير من مقدار الوقت لتنزيل المورد ، وتقليل استخدام البيانات للعميل ، وتحسين الوقت لعرض صفحاتك لأول مرة.
تحقق من وثائق خادم الويب الخاص بك حول كيفية تمكين الضغط:
- اباتشي: استخدم mod_deflate
- Nginx: استخدم ngx_http_gzip_module
باستخدام Eslint-plugin-response
يجب عليك استخدام ESLint لأي مشروع JavaScript تقريبًا. رد الفعل لا يختلف.
باستخدام eslint-plugin-react
، ستجبر نفسك على التكيف مع الكثير من القواعد في برمجة React التي يمكن أن تفيد الكود الخاص بك على المدى الطويل وتتجنب العديد من المشكلات الشائعة والمشكلات التي تحدث بسبب سوء كتابة التعليمات البرمجية.
اجعل تطبيقات الويب تتفاعل بسرعة مرة أخرى
لتحقيق أقصى استفادة من React ، تحتاج إلى الاستفادة من أدواتها وتقنياتها. يكمن أداء تطبيق الويب React في بساطة مكوناته. يمكن أن يؤدي التغلب على خوارزمية فروق العرض إلى ضعف أداء تطبيقك بطرق محبطة.
قبل أن تتمكن من تحسين تطبيقك ، ستحتاج إلى فهم كيفية عمل مكونات React وكيفية عرضها في المتصفح. تمنحك طرق دورة حياة React طرقًا لمنع المكون الخاص بك من إعادة العرض دون داع. تخلص من هذه الاختناقات وستحصل على أداء التطبيق الذي يستحقه المستخدمون.
على الرغم من وجود المزيد من الطرق لتحسين تطبيق ويب React ، إلا أن ضبط المكونات للتحديث فقط عند الحاجة يؤدي إلى تحسين الأداء الأفضل.
كيف يمكنك قياس أداء تطبيق الويب React وتحسينه؟ تشاركه في التعليقات أدناه.