React مسابقة مسابقة تحليل من HeadHunter كشك في HolyJs 2018

مرحبا في 24-25 سبتمبر ، تم عقد مؤتمر للمطورين المتقدمين في HolyJs https://holyjs-moscow.ru/ في موسكو. لقد جئنا إلى المؤتمر بموقفنا الذي أجرينا فيه الاختبار. كان هناك اختبار رئيسي - 4 جولات تصفيات وجولة أخيرة ، والتي لعبت عليها Apple Watch وبناة ليغو. وبشكل منفصل ، أجرينا مسابقة رد فعل المعرفة.


تحت القط - تحليل المهام مسابقة على رد فعل. سيتم إخفاء الخيارات الصحيحة تحت المفسد ، لذلك لا يمكنك قراءة التحليل فحسب ، ولكن يمكنك أيضًا التحقق من نفسك :)


الصورة


دعنا نذهب!


للراحة ، قمنا بتجميع الأسئلة في أقسام:


القسم 1. الفهم الأساسي لتشغيل this.setState وتحديث دورة حياة المكون:


السؤال 1.


      react-: 1) SetProps, SetState, ForceUpdate 2) ForceUpdate, SetState 3) ForceUpdate, SetState, Parent (re)render 4) ForceUpdate, SetState, directly call UpdateComponent 

الجواب

3) ForceUpdate ، SetState ، الأصل (إعادة) تقديم


السؤال 2.


  ,   this.setState({})  react 1)   ,  updating lifecycle 2)   ,    3) React    "Object cannot be empty" 4)    state   

الجواب

1) تم وضع علامة على العنصر القذر ، يتم استدعاء دورة حياة التحديث


تحليل السؤالين 1 و 2

للإجابة على السؤال ، سنقوم بتحليل جزأين:
1) طلب مكون خاص لتحديث دورة
2) طلب خارج المكون


يحتوي المكون نفسه على طريقتين لتحديث نفسه:
1) this.setState و this.forceUpdate. في هذه الحالة ، سيتم وضع علامة على المكون قذرًا وعلى علامة المصالحة ، إذا كانت الأولوية للتقديم ، فستبدأ دورة التحديث.


حقيقة مثيرة للاهتمام: this.setState({}) و this.forceUpdate مختلفان. عندما يتم this.setState({}) يتم استدعاء حلقة التحديث الكاملة ، على عكس this.forceUpdate ، عندما تبدأ حلقة التحديث دون shouldComponentUpdate. يمكن العثور على مثال على this.setState({}) هنا: https://codesandbox.io/s/m5jz2701l9 (إذا قمت باستبدال setState مع forceUpdate في المثال ، يمكنك معرفة كيفية تغير سلوك المكونات).


2) عند إعادة تقديم أصل المكون ، يقوم بإرجاع الجزء vDOM ، وجميع الأطفال الذين سوف يحتاجون إلى تحديث ، وسوف يطلق عليهم أيضًا دورة حياة تحديث كاملة. يمكن تجنب إعادة فرز الأصوات كاملة من الشجرة الفرعية عن طريق وصف shouldComponentUpdate أو عن طريق تعريف المكون كـ PureComponent.


السؤال 3


   Component  PureComponent (PC) 1) Component   ,    Pure 2) PC  SCU,  shallowEqual props  state 3) PC    ,    store 4)  PC    shouldComponentUpdate 

الإجابة والتحليل

2) PC تنفذ SCU ، وتجري الدعائم الضحلة والدولة


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


السؤال 4.


 this.setState(() => {}, () => {}) —       setState? 1) set   .    updating 2)       state 3) setState   1  

الإجابة والتحليل

2) سيتم استدعاء الوظيفة الثانية بعد تحديث الحالة


توجد طريقتان في دورة حياة Reacty: componentDidMount لحلقة التركيب و componentDidUpdate للتحديث ، حيث يمكنك إضافة بعض المنطق بعد تحديث المكون. على سبيل المثال ، قم بإجراء طلب http ، وقم بإجراء بعض التغييرات في النمط ، واحصل على مقاييس عناصر html ، ثم (set condition). إذا كنت تريد اتخاذ بعض الإجراءات بعد تغيير بعض الحقول في الولاية ، فعندئذٍ في طريقة componentDidUpdate يجب عليك كتابة أي مقارنة:


 componentDidUpdate(prevProp, prevState) { if (prevState.foo !== this.state.foo) { // do awesome things here } } 

أو يمكنك القيام بذلك عن طريق setState:


 setState( // set new foo {foo: 'baz'}, () => { // do awesome things here } ); 

كل نهج له إيجابيات وسلبيات (على سبيل المثال ، إذا قمت بتغيير setState في عدة أماكن ، فقد يكون من المناسب أن تكتب شرطًا مرة واحدة).


السؤال 5.


       render: class A extends React.PureComponent { render() { console.log('render'); return <div /> } } function Test() { return <A foo='bar' onClick={() => console.log('foo')} /> } const rootElement = document.getElementById("root"); ReactDOM.render(<Test />, rootElement); setTimeout(() => ReactDOM.render(<Test />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

الجواب

2) 2


السؤال 6.


       render: class A extends React.PureComponent { render() { console.log('render'); return <div /> } } function Test() { return <A foo='bar' /> } const rootElement = document.getElementById("root"); ReactDOM.render(<Test />, rootElement); setTimeout(() => ReactDOM.render(<Test />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

الجواب

1) 1


السؤال 7.


       render: class A extends React.PureComponent { componentDidMount() { console.log('render'); } render() { return <div /> } } const rootElement = document.getElementById("root"); ReactDOM.render(<A />, rootElement); setTimeout(() => ReactDOM.render(<A />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

الجواب

1) 1


تحليل الأسئلة 5-7

الأسئلة 5-7 ضرورية لنفس الشيء - للتحقق من فهم عمل PureComponent وتحديث المكونات عند نقل الدعائم. إذا قمنا داخل طريقة التجسيد بتمرير رد اتصال jsx ، فيصف ذلك مباشرةً في وظيفة التجسيد:


 render () { return <Button onClick={() => {}} />; } 

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


القسم 2. مفاتيح في رد الفعل


تحليل مفصل للمفاتيح التي نشرناها هنا: https://habr.com/company/hh/blog/352150/


السؤال 1.


     key,      ? 1)         key 2)    updating lifecycle 3)   key  4)    reconciliation 

الإجابة والتحليل

1) احذف المثيل السابق وقم بتركيب المثيل الجديد عند تغيير المفتاح


بدون استخدام المفتاح ، ستقوم الاستجابة بمقارنة قائمة العناصر في أزواج من الأعلى إلى الأسفل. إذا استخدمنا المفتاح ، فستحدث المقارنة على المفتاح المقابل. إذا ظهر مفتاح جديد ، فلن تتم مقارنة هذا المكون بأي شخص وسيتم إنشاؤه على الفور من البداية.
يمكنك استخدام هذه الطريقة حتى لو كان لدينا عنصر واحد: يمكننا تعيين <A key="1" /> ، وفي العرض التالي نحدد <A key="2" /> وفي هذه الحالة ، سيؤدي الرد إلى حذف <A key="1" /> وإنشاء من الصفر <A key="2" /> .


السؤال 2.


       this.prop.key? 1)  2)  3)   static getKey 

الإجابة والتحليل

2) لا


يمكن للمكون تعلم المفتاح من أبنائه ، والذي تم تمريره إليه كدعامة ، ولكن لا يمكن معرفة المفتاح الخاص به.


السؤال 3.


       render: class A extends React.PureComponent { componentDidMount() { console.log('render'); } render() { return <div /> } } const rootElement = document.getElementById("root"); ReactDOM.render(<A key='1' />, rootElement); setTimeout(() => ReactDOM.render(<A />, rootElement)); 1) 1 2) 2 3) 3 4) 0 

الإجابة والتحليل

2) 2


عند تغيير المفتاح ، سيتم إعادة تكوين المكون ، لذلك سيتم عرض التجسيد مرتين.


القسم 3. أسئلة حول jsx


السؤال 1.


   .           1)    prop / context 2)        3)  setParentProps 4)  static getParentRef 

الإجابة والتحليل

1) رد الاتصال في شكل سند / السياق
2) إزالة طبقة النموذج والعمل من خلالها


هناك نوعان من الإجابات الصحيحة. اختيار أي منهم في مسابقة سوف يحسب لك النقاط. هذا السؤال هو لمعرفة تدفق البيانات تتفاعل. يتم توزيع البيانات من أعلى إلى أسفل في شكل الدعائم أو السياق ، ويمكن أن تحتوي على رد اتصال ، والذي يمكن للمكون أدناه الاتصال به للتأثير على حالة النظام.
هناك طريقة أخرى تجمع بين إزالة النموذج والسياق والدعامة ، على سبيل المثال ، ربط رد فعل رد الفعل.
تأخذ هذه المكتبة نموذجًا مستمدًا من رد الفعل (redux). يضبط redux.store في موفر ، والذي يعين بالفعل مخزن في السياق. ثم يستخدم المطور HOC connect ، والذي يذهب إلى السياق ، ويشترك في تخزين (store.subscribe) ، وعندما يتغير المتجر ، يقوم mapStateToProps وظيفة mapStateToProps . إذا كانت البيانات قد تغيرت ، فإنه يضعها في الدعائم إلى كائن ملفوف.
في الوقت نفسه ، يتيح لك الاتصال تحديد mapDispatchToProps ، حيث يحدد المطور تلك الإجراءات التي يجب تمريرها إلى المكون. نحن ، بدورنا ، actionCreators من الخارج (بدون سياق) ، actionCreators (نلفهم في store.dispatch) ونمررهم كدعائم إلى المكون المُلف.


السؤال 2.


   props   jsx?     1)   2)   children 

الإجابة والتحليل

1) في أي


يمكنك نقل إلى أي. على سبيل المثال:


 <Button icon={<Icon kind='warning'/>}></Button> 

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


القسم 4. فهم متقدم setState


فيما يلي 3 أسئلة مرتبطة بقوة:


السؤال 1.


 this.state = {a: 'a'}; ... this.setState({a: 'b'}); this.setState({a: this.state.a + 1}) this.state? 1) {a: 'a1'} 2) {a: 'b1'} 3)   4) {a: 'a'} 

الجواب

3) لا توجد بيانات كافية


السؤال 2.


 this.state={a: 'a'} ... this.setState({a: 'b'}) this.setState(state => ({a: state.a + 1})) this.state? 1) {a: 'a1'} 2) {a: 'b1'} 3)   4) {a: 'ab1'} 

الجواب

2) {a: 'b1'}


السؤال 3.


    2 setState  componentDidUpdate  updating lifecycle   1) 1 2) 2 3) 3 4)   

الجواب

1) 1


تحليل الأسئلة 1-3

تم وصف جميع أعمال setState بالكامل هنا:
1) https://reactjs.org/docs/react-component.html#setstate
2) https://stackoverflow.com/questions/48563650/does-react-keep-the-order-for-state-updates/48610973#48610973


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


 this.state = {a: 'a'}; // a: 'a' ... this.state.a // a: 'a' this.setState({a: 'b'}); // a: 'b' +   .       this.state.a // a: 'a' this.setState({a: this.state.a + 1}) // a: 'a1' 

منذ التغييرات وقعت batchevo.
ولكن في نفس الوقت ، إذا تم استدعاء setState خارج معالجات التفاعل:


 this.state = {a: 'a'}; // a: 'a' ... this.state.a // a: 'a' this.setState({a: 'b'}); // a: 'b' +     this.state.a // a: 'b' this.setState({a: this.state.a + 1}) // a: 'b1' +     

بما أنه في هذه الحالة ، سيتم إرجاع التغييرات بشكل منفصل.


القسم 5. استرجاع


السؤال 1.


     action,  () => {} ? 1) .  action      type 2) ,   action      type 3) ,    middleware   action 4) ,       dispatch 

الإجابة والتحليل

3) نعم ، تحتاج إلى تحديد الوسيطة المخصصة لمثل هذا الإجراء


خذ عملية إعادة - thock أبسط مثال. جميع البرامج الوسيطة عبارة عن كتلة صغيرة من التعليمات البرمجية:
https://github.com/reduxjs/redux-thunk/blob/master/src/index.js#L2-L9


 return ({ dispatch, getState }) => next => action => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return next(action); }; 

كيف تعمل الوسيطة؟
يحصلون على السيطرة قبل وصول الإجراء إلى المتجر. لذلك ، فإن الإجراء الذي تم الكتابة فوقه سيتم أولاً الانتقال عبر سلسلة البرامج الوسيطة.
يقبل كل برنامج وسيط مثيل متجر ، والطريقة التالية ، التي تتيح لك إعادة توجيه الإجراء إلى أبعد من ذلك والإجراء نفسه.
إذا عالجت الوسيطة الإجراءات المخصصة ، مثل redux-thunk ، فإذا كانت هذه الوظيفة هي وظيفة ، فلن تقوم بإعادة توجيه الإجراء إلى أبعد من ذلك ، ولكنها "تغرق" ، بدلاً من ذلك ، تستدعي الإجراء باستخدام أساليب الإرسال و getState التي تم تمريرها إلى هناك.
ماذا سيحدث لو حدث رد فعل thux بعد العملية ، وهي وظيفة؟
قبل استدعاء المخفضات ، يخزن المتجر نوع الإجراء. يجب أن يستوفي الشروط التالية:
1) يجب أن يكون كائن
2) يجب أن يكون حقل نوع
3) يجب أن يكون حقل الكتابة من نوع السلسلة


إذا لم يتم استيفاء أحد الشروط ، فسوف يؤدي الإرجاع إلى حدوث خطأ.


أسئلة مكافأة:


مكافأة السؤال 1.


   ? class Todos extends React.Component { getSnapshotBeforeUpdate(prevProps, prevState) { return this.props.list.length - prevProps.list.length; } componentDidUpdate(a, b, c) { console.log(c); } ... } ReactDOM.render(<Todos list={['a','b']} />, app); setTimeout(() => ReactDOM.render(<Todos list={['a','b','a','b']} />, app), 0); a) 0 b) 1 c) 2 d) undefined 

الإجابة والتحليل

ج) 2


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


مكافأة السؤال 2.


        2,5 ? function Input() { const [text, setText] = useState("World!"); useEffect( () => { let id = setTimeout(() => { setText("Hello " + text); }, 1000); return () => { clearTimeout(id); }; }, [text] ); return ( <input value={text} onChange={e => { setText(e.target.value); }} /> ); } a) "World!" b) "Hello World!" c) "Hello Hello World!" d)    

الجواب

ج) "مرحبا العالم مرحبا!"


هذه بالفعل مسألة معرفة الميزات الجديدة في رد الفعل ؛ لم يكن في مسابقة لدينا. لنجرب في التعليقات لوصف بالتفصيل تشغيل الكود من السؤال الأخير :)

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


All Articles