رد فعل الخطافات - فوز أم خسارة؟

الصورة


مع إصدار React 16.6.0 الجديد ، ظهر HOOKS (PROPOSAL) في الوثائق. وهي متوفرة الآن بتفاعل 17.0.0-alpha وتمت مناقشتها في RFC المفتوح : React Hooks . دعونا نرى ما هو ولماذا هناك حاجة تحت القطع.


نعم إنه RFC ويمكنك التأثير على التنفيذ النهائي الذي يناقش مع منشئي رد الفعل لماذا اختاروا هذا النهج أو ذاك.


دعونا نلقي نظرة على شكل الخطاف القياسي:


import { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } 

حاول التفكير في هذا الرمز ، فهذا عبارة عن جملة تشويقية وبنهاية المقالة ستفهم بالفعل ما يعنيه. أول شيء يجب أن تعرفه هو أن هذا لا يكسر التوافق العكسي وربما سيتم إضافتهم في 16.7 بعد جمع التعليقات والاقتراحات في RFC.


كما يؤكد الرجال ، هذه ليست خطة لقص الطبقات من الكاشف.


أيضا ، الخطافات لا تحل محل المفاهيم الحالية للتفاعل ، كل شيء في مكان الدعائم / الحالة / السياق / المرجع. هذه مجرد طريقة أخرى لاستخدام قوتهم.


الدافع


تحل الخطافات للوهلة الأولى المشاكل غير المتصلة التي ظهرت بدعم من عشرات الآلاف من المكونات على مدار 5 سنوات من الفيسبوك.


إن أصعب شيء هو إعادة استخدام المنطق في المكونات ذات الحالة ، فالتفاعل ليس لديه طريقة لإرفاق سلوك قابل لإعادة الاستخدام للمكون (على سبيل المثال ، توصيله بالمستودع). إذا كنت تعمل مع React ، فأنت تعرف مفهوم HOC (مكون عالي الترتيب) أو تقديم الدعائم. هذه أنماط جيدة بما يكفي ، ولكن في بعض الأحيان يتم استخدامها بشكل مفرط ، فهي تتطلب إعادة هيكلة المكونات بحيث يمكن استخدامها ، مما يجعل الرمز أكثر تعقيدًا في العادة. يجدر النظر في تطبيق رد فعل نموذجي وسيصبح من الواضح ما هو على المحك.


الصورة


وهذا ما يسمى الجحيم المغلف - الجحيم المغلف.


تطبيق من HOCs وحده أمر طبيعي في الحقائق الحالية ، فقد ربطوا المكون بالمتجر / الموضوع / التعريب / العرقوب المخصص ، أعتقد أن الجميع يعرف ذلك.


يصبح من الواضح أن التفاعل يحتاج إلى آلية بدائية أخرى لفصل المنطق.


باستخدام الخطافات ، يمكننا استخلاص حالة المكون بحيث يمكن اختباره وإعادة استخدامه. تسمح لك الخطافات بإعادة استخدام منطق الحالة دون تغيير التسلسل الهرمي للمكونات. هذا يسهل تبادل الروابط بين العديد من المكونات أو النظام بأكمله. أيضًا ، تبدو مكونات الفصل مخيفة إلى حد ما ، فنحن نصف طرق دورة حياة componentDidMount / يجب أن يكون shouldComponentUpdate / componentDidUpdate shouldComponentUpdate ، وحالة المكون ، وخلق طرق للعمل مع الحالة / الجانب ، وطرق الربط shouldComponentUpdate componentDidUpdate ، وهكذا يمكن أن تستمر shouldComponentUpdate . عادة ، تتجاوز هذه المكونات خطوط س ، حيث يصعب فهم س.


تسمح لك الخطافات بفعل الشيء نفسه عن طريق كسر المنطق بين المكونات إلى وظائف صغيرة واستخدامها داخل المكونات.


الطبقات صعبة للناس وللسيارات


في مراقبة دروس الفيسبوك هي عقبة كبيرة عند تعلم رد فعل. تحتاج إلى فهم كيفية عمل this ، ولا يعمل كما هو الحال في لغات البرمجة الأخرى ، يجب أن تتذكر أيضًا معالجات الأحداث الملزمة. بدون جمل تركيبية مستقرة ، تبدو الشفرة مطولة للغاية. يفهم الناس أنماط الدعائم / الحالة وما يسمى بتدفق البيانات من أعلى إلى أسفل ، ولكن يصعب فهم الفئات.


خاصة إذا لم تقتصر على القوالب ، منذ وقت ليس ببعيد جرب الرجال من التفاعل تجربة تخطيط المكونات مع Prepack وشاهدوا نتائج واعدة ، ولكن مع ذلك ، تسمح لك مكونات الفصل بإنشاء أنماط سيئة غير مقصودة تجعل هذه التحسينات تختفي ، كما لا يتم ترحيل الفصول جيدًا عندما فصول إعادة التحميل الساخنة تجعله غير موثوق به. بادئ ذي بدء ، أراد الرجال توفير واجهة برمجة تطبيقات تدعم جميع التحسينات وتعمل بشكل جيد مع إعادة تشغيل سريعة.


نلقي نظرة على الخطافات


هوك الدولة


يعرض الرمز أدناه فقرة وزرًا ، وإذا نقرنا على الزر ، فسيتم زيادة القيمة في الفقرة.


 import { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } 

من هذا يمكننا أن نستنتج أن هذا الخطاف يعمل بالمثل مع مفهوم مثل state .
هناك طريقة أكثر تفصيلاً useState الأسلوب useState يأخذ وسيطة واحدة ، وهذه هي القيمة الافتراضية وترجع tuple الذي توجد فيه القيمة نفسها وطريقة تغييرها ، على عكس setState ، لن يقوم setCount بدمج القيم ، ولكن ببساطة تحديثها. يمكننا أيضًا استخدام إعلانات الدولة المتعددة ، على سبيل المثال:


 function ExampleWithManyStates() { // Declare multiple state variables! const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]); // ... } 

وبالتالي ، فإننا ننشئ عدة ولايات في وقت واحد ولا نحتاج إلى التفكير في كيفية تفكيكها بطريقة أو بأخرى. وبالتالي ، يمكن تمييز أن الخطافات هي وظائف تسمح لك "بالاتصال" بشرائح مكونات الفئة ، تمامًا كما لا تعمل الخطافات داخل الفئات ، فمن المهم تذكر ذلك.


خطاف تأثير


في كثير من الأحيان في مكونات الفصل ، نقوم بعمل وظائف الآثار الجانبية ، على سبيل المثال ، الاشتراك في الأحداث أو تقديم طلبات للحصول على البيانات ، لذلك عادة ما نستخدم طرق componentDidUpdate / componentDidUpdate / componentDidUpdate التحديث


 import { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); } 

عندما useEffect نطلب من رد الفعل القيام `` بتأثير جانبي '' بعد تحديث التغييرات في شجرة DOM. يتم الإعلان عن التأثيرات داخل المكون ، وبالتالي يمكنهم الوصول إلى الدعائم / الحالة. علاوة على ذلك ، يمكننا إنشاؤها بنفس الطريقة التي تريدها تمامًا.


 function FriendStatusWithCounter(props) { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); const [isOnline, setIsOnline] = useState(null); useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); function handleStatusChange(status) { setIsOnline(status.isOnline); } // ... 

على الفور يجدر الانتباه إلى التأثير الجانبي الثاني فيه ، نعيد الوظيفة ، نقوم بذلك من أجل تنفيذ بعض الإجراءات بعد أن يقوم المكون بإلغاء التثبيت ، في api الجديد يسمى هذا بالتأثيرات مع التنظيف. يمكن أن ترجع التأثيرات الأخرى أي شيء.


قواعد هوك


الخطافات هي وظائف جافا سكريبت فقط ، ولكنها تتطلب قاعدتين فقط:


  • يجب تنفيذ الخطافات في أعلى التسلسل الهرمي للوظائف (وهذا يعني أنه لا يجب استدعاء الخطافات في الظروف والحلقات ، وإلا فإن التفاعل لا يمكن أن يضمن ترتيب تنفيذ الخطافات)
  • ربط الخطافات فقط في وظائف التفاعل أو المكونات الوظيفية أو ربط الخطافات من الخطافات المخصصة (هذا أدناه).
    لاتباع هذه القواعد ، أنشأ الرجال من فريق رد الفعل مكونًا إضافيًا لِطِرًا سيؤدي إلى حدوث خطأ في حالة استدعاء الخطافات في مكونات الصف أو في الحلقات والظروف.

خطافات مخصصة


في الوقت نفسه ، نريد إعادة استخدام منطق المكونات ذات الحالة ، وعادة ما يتم استخدام أنماط HOC أو تقديم الدعائم لهذا الغرض ، ولكنها تنشئ حجمًا إضافيًا لتطبيقنا.
على سبيل المثال ، نصف الوظيفة التالية:


 import { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); function handleStatusChange(status) { setIsOnline(status.isOnline); } useEffect(() => { ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); }; }); return isOnline; } 

أدرك هذا الرمز ، سيكون خطافًا مخصصًا يمكننا استدعاؤه في مكونات مختلفة. على سبيل المثال ، مثل هذا:


 function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; } 

أو نحو ذلك


 function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); } 

على أي حال ، نعيد استخدام حالة المكون ، فكل استدعاء لوظيفة useFriendStatus ينشئ حالة معزولة. وتجدر الإشارة أيضًا إلى أن بداية هذه الوظيفة تبدأ بكلمة استخدام ، مما يعني أنها خطاف. نوصي باتباع هذا التنسيق. يمكنك كتابة خطافات مخصصة لأي شيء ، والرسوم المتحركة / الاشتراكات / المؤقتات وأكثر من ذلك بكثير.


هناك زوجان من الخطافات.


استخدام المحتوى


يتيح لك useContext استخدام القيمة المرجعة المعتادة بدلاً من تقديمها ، وهو السياق الذي نريد استرجاعه فيه وسيعيده إلينا ، حتى نتمكن من التخلص من جميع HOCs التي مرت السياق إلى الدعائم.


 function Example() { const locale = useContext(LocaleContext); const theme = useContext(ThemeContext); // ... } 

والآن يمكننا فقط استخدام كائن السياق في القيمة المرجعة.


استخدام


 const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], ); 

كم مرة يجب عليك إنشاء مكون من فئة فقط لحفظ مرجع إلى أسلوب؟ لا داعي للقيام بذلك بعد الآن ، يمكننا استخدام useCallback ولن يتم إعادة رسم مكوناتنا لأنه وصل رابط جديد إلى onClick.


استخدام


نعيد القيمة المستحدثة ، القيمة المستدقة تعني أنه يتم حسابها فقط عندما تتغير إحدى الوسيطات ، في المرة الثانية لن يتم حساب نفس الشيء.


 const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]); 

نعم ، يجب عليك هنا تكرار القيم في المصفوفة حتى يفهم الخطاف أنها لم تتغير.


استخدام


useRef قيمة متحولة ، حيث سيتم تهيئة الحقل .current مع الوسيطة الأولى ، سيظل الكائن موجودًا طالما كان المكون موجودًا.
المثال الأكثر شيوعًا عند التركيز على الإدخال


 function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` points to the mounted text input element inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); } 

استخدام طرق فعالة


useImperativeMethods قيمة المثيل الذي يتم تمريره من الأصل ويستخدم المرجع مباشرة. كما هو الحال دائمًا ، يجب تجنب الروابط المباشرة ويجب استخدام forwardRef


 function FancyInput(props, ref) { const inputRef = useRef(); useImperativeMethods(ref, () => ({ focus: () => { inputRef.current.focus(); } })); return <input ref={inputRef} ... />; } FancyInput = forwardRef(FancyInput); 

في هذا المثال ، يمكن للمكون الذي FancyInput استدعاء fancyInputRef.current.focus() .


استخدام


useMutationEffect مشابه جدًا لـ useEffect باستثناء أنه يبدأ بشكل متزامن في المرحلة عندما يغير التفاعل قيم DOM قبل تحديث المكونات المجاورة ، يجب استخدام هذا الخطاف لإجراء طفرات DOM.
من الأفضل تفضيل استخدام التأثير لمنع حجب التغييرات المرئية.


استخدام LayoutEffect


useLayoutEffect مشابه لـ useEffect باستثناء أنه يعمل بشكل متزامن بعد كل تحديثات DOM وإعادة العرض المتزامن. يتم تطبيق التحديثات المخطط لها في useLayoutEffect بشكل متزامن قبل أن يتمكن المتصفح من رسم العناصر. يجب عليك أيضًا محاولة استخدام useEffect القياسي حتى لا تمنع التغييرات المرئية.


استخدامالحد


useReducer هو خطاف لإنشاء مخفض يعيد الحالة والقدرة على إرسال التغييرات:


 const [state, dispatch] = useReducer(reducer, initialState); 

إذا كنت تفهم كيفية عمل Redux ، فإنك تفهم كيف يعمل useReducer . نفس المثال الذي كان مع العداد أعلاه فقط من خلال useReducer :


 const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'reset': return initialState; case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; } } function Counter({initialCount}) { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset'})}> Reset </button> <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); } 

يستخدم UseReducer أيضًا ثلاث وسيطات ، وهذا هو action الذي يجب تنفيذه عند تهيئة المخفض:


 const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'reset': return {count: action.payload}; case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; } } function Counter({initialCount}) { const [state, dispatch] = useReducer( reducer, initialState, {type: 'reset', payload: initialCount}, ); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'reset', payload: initialCount})}> Reset </button> <button onClick={() => dispatch({type: 'increment'})}>+</button> <button onClick={() => dispatch({type: 'decrement'})}>-</button> </> ); } 

يمكننا أيضًا إنشاء سياق في هذا المخفض واستخدامه من خلال ربط useContext لاستخدامه في جميع أنحاء التطبيق ، وهذا يبقى للواجب المنزلي.


لتلخيص


الخطافات هي طريقة قوية إلى حد ما لحل جحيم الغلاف وحل العديد من المشاكل ، ولكن يمكن استخدامها جميعًا بنفس تعريف نقل الارتباط . تبدأ الآن بالفعل في ظهور مجموعات من الخطافات للاستخدام أو هذه المجموعة . يمكنك معرفة المزيد عن الخطافات في الوثائق .

Source: https://habr.com/ru/post/ar428317/


All Articles