Reagieren Sie auf dem HolyJs 2018 am HeadHunter-Stand auf das Quiz des Wettbewerbs

Hallo. Am 24. und 25. September fand in Moskau eine Konferenz der Front-End-Entwickler von HolyJ https://holyjs-moscow.ru/ statt. Wir kamen mit unserem Stand zur Konferenz, an dem wir ein Quiz abhielten. Es gab ein Hauptquiz - 4 Qualifikationsrunden und 1 Endrunde, in denen die Apple Watch- und Lego-Konstrukteure gespielt wurden. Und separat haben wir ein Quiz zum Reagieren von Wissen durchgeführt.


Unter Cat - Parsing Quiz Aufgaben reagieren. Die richtigen Optionen werden unter dem Spoiler versteckt, sodass Sie nicht nur die Analyse lesen, sondern auch sich selbst überprüfen können :)


Bild


Lass uns gehen!


Der Einfachheit halber haben wir die Fragen in Abschnitte unterteilt:


Abschnitt 1. Grundlegendes Verständnis der Funktionsweise von this.setState und Aktualisieren des Komponentenlebenszyklus:


Frage 1.


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

Die Antwort

3) ForceUpdate, SetState, Parent (re) rendern


Frage 2.


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

Die Antwort

1) Die Komponente ist als verschmutzt markiert, der Aktualisierungslebenszyklus wird aufgerufen


Analyse der Fragen 1 und 2

Um die Frage zu beantworten, werden wir 2 Teile analysieren:
1) Eigene Komponentenanforderung zum Aktualisieren des Zyklus
2) Anfrage außerhalb der Komponente


Die Komponente selbst hat zwei Möglichkeiten, sich selbst zu aktualisieren:
1) this.setState und this.forceUpdate. In diesem Fall wird die Komponente als verschmutzt markiert und im Häkchen Reconcilliation wird ein Aktualisierungszyklus gestartet, wenn sie beim Rendern Priorität hat.


Interessante Tatsache: this.setState({}) und this.forceUpdate sind unterschiedlich. Wenn this.setState({}) aufgerufen wird, wird im Gegensatz zu this.forceUpdate die vollständige Aktualisierungsschleife this.forceUpdate , wenn die Aktualisierungsschleife ohne die Methode shouldComponentUpdate gestartet wird. Ein Beispiel für die Arbeit von this.setState({}) finden Sie hier: https://codesandbox.io/s/m5jz2701l9 (wenn Sie im Beispiel setState durch forceUpdate ersetzen, können Sie sehen, wie sich das Verhalten der Komponenten ändert).


2) Wenn das übergeordnete Element der Komponente erneut gerendert wird, gibt es den vDOM-Teil zurück, alle untergeordneten Elemente, die aktualisiert werden müssen, und sie werden auch als vollständiger Aktualisierungslebenszyklus bezeichnet. Eine vollständige Nachzählung des Teilbaums kann vermieden werden, indem shouldComponentUpdate beschrieben oder die Komponente als PureComponent definiert wird.


Frage 3


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

Antwort und Analyse

2) PC implementiert SCU, führt flache Gleiche Requisiten und Status durch


Wie bereits erwähnt, wird beim (erneuten) Rendern des übergeordneten Elements der gesamte Teilbaum an den aktualisierenden Lebenszyklus gesendet. Stellen Sie sich vor, Sie haben das Stammelement aktualisiert. In diesem Fall müssen Sie entsprechend dem Ketteneffekt fast den gesamten Reaktionsbaum aktualisieren. Um unnötige Aktualisierungen zu optimieren und nicht zu senden, gibt es in Reaktion eine Methode shouldComponentUpdate , mit der Sie true zurückgeben können, wenn die Komponente aktualisiert werden soll, andernfalls false. Um Vergleiche in der Reaktion zu vereinfachen, können Sie von PureComponent erben, um sofort bereit zu sein, shouldComponentUpdate , das alle Requisiten und shouldComponentUpdate , die in die Komponente shouldComponentUpdate , shouldComponentUpdate von Referenzen (wenn es sich um Objekttypen handelt) oder nach Werten (wenn es sich um shouldComponentUpdate handelt) vergleicht.


Frage 4.


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

Antwort und Analyse

2) Die zweite Funktion wird nach dem Aktualisieren des Status aufgerufen


Im React-Lifecycle gibt es zwei Methoden: componentDidMount für die Mounting-Schleife und componentDidUpdate für die Aktualisierung, wobei Sie nach der Aktualisierung der Komponente eine Logik hinzufügen können. Stellen Sie beispielsweise eine http-Anfrage, nehmen Sie einige Stiländerungen vor, rufen Sie die Metriken der HTML-Elemente ab und machen Sie (nach Bedingung) setState. Wenn Sie nach dem Ändern bestimmter Felder im Status eine Aktion ausführen möchten, müssen Sie in der componentDidUpdate Methode entweder einen Vergleich schreiben:


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

Oder Sie können es mit setState tun:


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

Jeder Ansatz hat Vor- und Nachteile (wenn Sie beispielsweise setState an mehreren Stellen ändern, ist es möglicherweise bequemer, eine Bedingung einmal zu schreiben).


Frage 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 

Die Antwort

2) 2


Frage 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 

Die Antwort

1) 1


Frage 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 

Die Antwort

1) 1


Analyse der Fragen 5-7

Fragen 5–7 sind für dasselbe erforderlich - um das Verständnis der Arbeit von PureComponent und die Aktualisierung der Komponenten bei der Übertragung von Requisiten zu überprüfen. Wenn wir innerhalb der Render-Methode einen jsx-Rückruf übergeben, der dies direkt in der Render-Funktion beschreibt:


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

Dann aktualisiert jedes Rendering des übergeordneten Elements den angegebenen Klick-Handler. Dies liegt daran, dass bei jedem Rendern eine neue Funktion mit einem eindeutigen Link erstellt wird. Im Vergleich zu PureComponent werden die neuen Requisiten nicht den alten entsprechen und Sie müssen die Komponente aktualisieren. Wenn alle Prüfungen bestanden sind und shouldComponentUpdate false zurückgibt, erfolgt die Aktualisierung nicht.


Abschnitt 2. Schlüssel in Reaktion


Eine detaillierte Analyse der hier veröffentlichten Schlüssel: https://habr.com/company/hh/blog/352150/


Frage 1.


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

Antwort und Analyse

1) Löschen Sie die vorherige Instanz und mounten Sie die neue, wenn Sie den Schlüssel ändern


Ohne Schlüssel wird durch Reagieren die Liste der Elemente paarweise von oben nach unten verglichen. Wenn wir den Schlüssel verwenden, erfolgt der Vergleich mit dem entsprechenden Schlüssel. Wenn ein neuer Schlüssel angezeigt wurde, wird eine solche Komponente mit niemandem verglichen und sofort von Grund auf neu erstellt.
Sie können diese Methode auch dann verwenden, wenn wir 1 Element haben: Wir können <A key="1" /> , im nächsten Rendering geben wir <A key="2" /> und in diesem Fall wird durch Reagieren <A key="1" /> gelöscht. <A key="1" /> und erstellen Sie von Grund auf <A key="2" /> .


Frage 2.


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

Antwort und Analyse

2) Nein


Die Komponente kann den Schlüssel von ihren untergeordneten Elementen lernen, die ihr als Requisite übergeben wurden, kann jedoch nichts über ihren Schlüssel lernen.


Frage 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 

Antwort und Analyse

2) 2


Beim Ändern des Schlüssels wird die Komponente neu erstellt, sodass das Rendern zweimal angezeigt wird.


Abschnitt 3. Fragen zu jsx


Frage 1.


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

Antwort und Analyse

1) Rückruf in Form von Requisite / Kontext
2) Entfernen Sie die Ebene des Modells und arbeiten Sie sie durch


Es gibt zwei richtige Antworten. Wenn Sie einen von ihnen in einem Quiz auswählen, erhalten Sie Punkte. Diese Frage dient der Kenntnis des Datenflusses. Daten von oben nach unten werden in Form von Requisiten oder Kontext verteilt. Sie können einen Rückruf enthalten, den die folgende Komponente aufrufen kann, um den Status des Systems zu beeinflussen.
Eine andere Methode, die Modellentfernung, Kontext und Requisite kombiniert, ist beispielsweise die React-Redux-Bindung.
Diese Bibliothek verwendet ein Modell aus React (Redux). Legt redux.store in Provider fest, wodurch der Speicher tatsächlich im Kontext festgelegt wird. Anschließend verwendet der Entwickler die HOC-Verbindung, die in den Kontext eingeht, Änderungen zum Speichern (store.subscribe) abonniert und bei Änderungen des Speichers die Funktion mapStateToProps . Wenn sich die Daten geändert haben, werden sie in Requisiten für das umschlossene Objekt festgelegt.
Gleichzeitig können Sie mit mapDispatchToProps angeben, wobei der Entwickler die actionCreators angibt, die an die Komponente übergeben werden müssen. Wir wiederum empfangen sie von außen (ohne Kontext), binden die actionCreators an den Store (wir verpacken sie in store.dispatch) und übergeben sie als Requisiten an die verpackte Komponente.


Frage 2.


   props   jsx?     1)   2)   children 

Antwort und Analyse

1) In jedem


Sie können zu jedem übertragen. Zum Beispiel:


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

Zeichnet eine Schaltfläche mit einem Symbol. Dieser Ansatz ist sehr praktisch, um der Komponente das Recht zu geben, die Position verschiedener Elemente relativ zueinander zu steuern, anstatt eine untergeordnete Requisite zu sortieren.


Abschnitt 4. Erweitertes Verständnis von setState


Hier sind 3 stark verwandte Fragen:


Frage 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'} 

Die Antwort

3) Nicht genügend Daten


Frage 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'} 

Die Antwort

2) {a: 'b1'}


Frage 3.


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

Die Antwort

1) 1


Analyse der Fragen 1-3

Die gesamte Arbeit von setState wird hier vollständig beschrieben:
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


Tatsache ist, dass setState nicht synchron erfolgt.
Und wenn setState mehrere Aufrufe hintereinander hat, hängt die Ausführung von setState davon ab, ob wir uns innerhalb der React-Lifecycle-Methode, der Handlerfunktion des React-Ereignisses (onChange, onClick) befinden oder nicht.
In React-Handlern arbeitet setState stapelweise (Änderungen werden erst dann ausgeführt, wenn die benutzerdefinierten Funktionen im Aufrufstapel beendet sind und wir auf die Funktionen zugreifen, die unsere Ereignishandler- und Lebenszyklusmethoden aufgerufen haben). Sie rollen nacheinander. Wenn wir uns also im React-Handler befinden, erhalten wir:


 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' 

da die Änderungen aufgetreten sind batchevo.
Aber gleichzeitig, wenn setState außerhalb von React-Handlern aufgerufen wurde:


 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' +     

Da in diesem Fall die Änderungen separat gewürfelt werden.


Abschnitt 5. Redux


Frage 1.


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

Antwort und Analyse

3) Ja, Sie müssen für eine solche Aktion eine benutzerdefinierte Middleware definieren


Nehmen Sie Redux-Thunk als einfachstes Beispiel. Alle Middleware ist ein kleiner Codeblock:
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); }; 

Wie funktioniert Middleware?
Sie erhalten die Kontrolle, bevor die Aktion im Geschäft eintrifft. Daher wird eine überschriebene Aktion zuerst die Middleware-Kette durchlaufen.
Jede Middleware akzeptiert eine Speicherinstanz, die nächste Methode, mit der Sie die Aktion weiterleiten können, und die Aktion selbst.
Wenn Middleware benutzerdefinierte Aktionen wie Redux-Thunk verarbeitet, leitet die Aktion, wenn sie eine Funktion ist, die Aktion nicht weiter, sondern "übertönt" sie, sondern ruft die Aktion mit den dort übergebenen Methoden dispatch und getState auf.
Was würde passieren, wenn Redux-Thunk als nächstes eine Aktion ausführen würde, was eine Funktion ist?
Speichern Sie vor dem Aufrufen von Reduzierern die Art der Aktion. Es muss folgende Bedingungen erfüllen:
1) Es muss ein Objekt sein
2) Es sollte ein Typfeld haben
3) Das Typfeld muss vom Typ string sein


Wenn eine der Bedingungen nicht erfüllt ist, gibt redux einen Fehler aus.


Bonusfragen:


Bonusfrage 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 

Antwort und Analyse

c) 2


getSnapshotBeforeUpdate ist eine selten verwendete Funktion in react, mit der Sie einen Snapshot getSnapshotBeforeUpdate können, der dann an componentDidUpdate übergeben wird. Diese Methode wird benötigt, um bestimmte Daten vorab zu berechnen, auf deren Grundlage Sie beispielsweise eine Abrufanforderung stellen können.


Bonusfrage 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)    

Die Antwort

c) "Hallo Hallo Welt!"


Dies ist bereits eine Frage der Kenntnis neuer Funktionen in Reaktion, es war nicht in unserem Quiz. Lassen Sie uns in den Kommentaren versuchen, die Funktionsweise des Codes aus der letzten Frage detailliert zu beschreiben :)

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


All Articles