Wissenswertes über React.js / Sudo Null IT-News

Ein paar Worte zur Motivation, diesen Artikel zu schreiben. Die meisten Dinge, über die ich hier sprechen möchte, finden Sie in der React-Dokumentation. Aber während ich in den letzten Jahren Interviews geführt habe, habe ich festgestellt, dass viele Entwickler aus irgendeinem Grund nichts davon wissen, vielleicht haben sie einfach nicht sorgfältig gelesen oder dem wurde in der Dokumentation selbst nicht genug Aufmerksamkeit geschenkt. Deshalb habe ich mich entschieden, hier ein paar Punkte zu sammeln und sie herunterzubrechen, damit diejenigen, die diesen Artikel lesen, beginnen, React ein wenig besser zu verstehen und beginnen, bestimmte Tools bewusster in ihrer Arbeit einzusetzen. Es wird auch für diejenigen nützlich sein, die sich auf ein Interview vorbereiten und nicht das Gesicht verlieren wollen, wenn sie von der Reaktion umgangen werden.

Die return-Funktion zum Zurücksetzen in useEffect wird öfter ausgelöst, als Sie denken

Viele Entwickler denken, dass die Funktion, die wir in useEffect zurückgeben, wie eine Lebenszyklusmethode von componentWillUnmount funktioniert und nur ausgelöst wird, wenn die Komponente ausgehängt wird, aber das ist nicht ganz richtig. Zusätzlich zum Aushängen der Komponente funktioniert es auch jedes Mal, wenn die Komponente gerendert wird, wenn Sie keine Abhängigkeitsliste übergeben oder jedes Mal, wenn ein Element aus der Abhängigkeitsliste geändert wird. In diesem Fall funktioniert die zurückgegebene Funktion zuerst und dann der Effektkörper.

Beispiel auf Codesandbox

Warum das so ist: Die Entwickler von React haben sich entschieden, in useEffect (fast) die gesamte Funktionalität der Lifecycle-Methoden zu implementieren. Stellen Sie sich eine Situation vor, in der Sie eine Art Zeitüberschreitung festlegen müssen, die irgendwie mit dem Status der Komponente funktionieren sollte. Wie würden Sie es in einer Klassenbean machen:

componentDidMount() {const {stateForTimer} = this.state; this.timer = setTimeout(() => console.log(stateForTimer), 1000); }

  • In der Komponente DidUpdate würden wir diesen Timer zurücksetzen und erneut setzen, wenn wir dies nicht tun, hat der Timer einen irrelevanten Zustand.

componentDidUpdate () { const { stateForTimer } = this.state; clearTimeout (this.timer); this.timer = setTimeout(() => console.log(stateForTimer), 1000); }

  • in componentWillUnmount kündigen wir den Timer, weil wir nicht wollen, dass er funktioniert, wenn wir nicht bereits eine Komponente auf dem Bildschirm haben.

componentWillUnmount () { clearTimeout (this.timer); }

  • Aber auf diese Weise funktioniert unser Timer bei jedem erneuten Rendern, in der übergeordneten Komponente, damit dies nicht passiert, können wir PureComponent anstelle von Component verwenden

Standardklasse ClassComponentTimer exportieren erweitert React.PureComponent { constructor() { super(); this.state = { stateForTimer: “Status für Timer” }; dieser Timer = null; } componentDidMount() {const {stateForTimer} = this.state; this.timer = setTimeout(() => console.log(stateForTimer), 1000); } componentDidUpdate() {const {stateForTimer} = this.state; clearTimeout (this.timer); this.timer = setTimeout(() => console.log(stateForTimer), 1000); } componentWillUnmount() { clearTimeout(this.timer); } inputHandler = (e) => { this.setState ({ stateForTimer: e.target.value }); }; render() { return (

Klassentimer

); } }

Stimmen Sie zu, es stellte sich als ziemlich ausführlich heraus.

Sie haben vielleicht bemerkt, dass wir den Timer 2 Mal abbestellen und auch 2 Mal abonnieren. Um uns also nicht zu wiederholen, haben die React-Entwickler diesen Mechanismus in Hooks an einer Stelle zusammengefasst, und jetzt wird unser Timer zurückgesetzt, wenn ein erneutes Rendern auftritt oder, wenn es eine Liste von Abhängigkeiten gibt, wenn sich die Abhängigkeit ändert, um zu vermeiden, dass mit veralteten Dateien gearbeitet wird Daten und beim Unmounten der Komponente, so dass es keine Seiteneffekte gab, die wir nicht mehr wirklich brauchen.

Standardfunktion exportieren App() { const [stateForTimer, setStateForTimer] = useState(“Zustand für Timer”); useEffect(() => { const timeout = setTimeout(() => console.log(stateForTimer), 1000); return () => clearTimeout(timeout); }, [stateForTimer]); const inputHandler = (e) => { setStateForTimer (e.target.value); }; return (

Funktionstimer

); }

In puncto Prägnanz gewinnen sicherlich Komponenten an Haken.

Der gesamte Code, der innerhalb einer funktionalen Komponente aufgerufen wird, wird bei jedem Rendern aufgerufen.

Seien Sie vorsichtig, wenn Sie Code innerhalb einer funktionalen Komponente schreiben, da er bei jedem erneuten Rendern aufgerufen wird.

Beispiel auf Codesandbox

Das bedeutet, dass einige komplexe Berechnungen nicht direkt in der Komponente durchgeführt werden sollten und Seiteneffekte überhaupt nicht durchgeführt werden sollten, da sie unkontrolliert arbeiten, es ist besser, dies in useEffect oder in useMemo zu tun.

Richtig, wenn wir die Komponente in ein Memo packen, funktioniert der Code innerhalb der Komponente nur, wenn sich der Zustand oder die Props ändern, aber es ist immer noch besser, die Berechnungen und Nebenwirkungen useEffect oder useMemo zu überlassen, weil wir genau steuern können, was wir tun müssen diesen Code erneut aufrufen, indem Sie .

Das Aufrufen von Funktionen in useState funktioniert bei jedem erneuten Rendern

Aus dem gleichen Grund sollten Sie komplexe Berechnungen und Seiteneffekte nicht direkt in einer Komponente durchführen, Sie sollten keine Funktionen innerhalb von useState aufrufen.

Beispiel auf Codesandbox

Wenn Sie einen Startwert für Ihren Status berechnen müssen, können Sie ihn in eine anonyme Funktion einfügen, die dann nur funktioniert, wenn die Komponente gemountet ist.

importiere { useState } aus “reagieren”; const twoSquared = () => { console.log(“mach mal ein bisschen Mathe”); Rückgabe 3 * 3; }; Standardfunktion exportieren StateOnce() { const [nine] = useState(() => twoSquared()); return (

3 * 3 = {nine}

); }

setState in funktionalen Komponenten kann eine Funktion annehmen

Im Hauptteil der Dokumentation findet sich dazu überhaupt kein Wort (zumindest habe ich es nicht gefunden), es wird nur in der ausführlichen API von Hooks erwähnt, sondern nur, dass man eine Funktion an setState und dann übergeben kann Holen Sie sich den vorherigen Zustandswert als Argument. Aber es wird kein Wort gesagt, warum es überhaupt nötig ist. Und die Sache ist die, dass setState eine asynchrone Operation ist, und wenn Sie beispielsweise in einer Schleife versuchen, mit dem aktuellen Statuswert zu arbeiten, erhalten Sie denselben Status so oft, wie Sie in dieser Schleife iterieren. Das Übergeben einer Funktion an setState behebt dieses Problem.

5 mal gedruckt 5for (let i = 1; i <= 5; i++) { setCount(count + 1); } Anzeige von 1 bis 5 für (let i = 1; i <= 5; i++) { setCount((prevCount) => prevCount + 1); }

Das Beispiel ist ein wenig erfunden, aber es kann eine Situation geben, in der Sie ein Array durchlaufen und setState für jedes Element dieses Arrays aufrufen müssen – das ist bereits etwas Realistischeres.

Codebeispiel auf codesandbox

Zusätzlich zu useEffect gibt es auch einen speziellen Hook useLayoutEffect

Sowohl useLayoutEffect als auch useEffect funktionieren nach dem Rendern, aber im Gegensatz zu useEffect arbeiten sie synchron.

Das bedeutet, dass der Browser bei Verwendung von useEffect etwas Zeit hat, um Inhalte zu rendern, was bedeutet, dass wir, wenn wir versuchen, etwas zu rendern, und in useEffect zum Beispiel verfolgen, was wir versuchen zu rendern und abzufangen es und ziehen Sie stattdessen einen anderen Wert, dann sehen wir ein leichtes Blinken. Aber es ist besser, ein Beispiel einmal zu sehen, als seine Beschreibung hundertmal zu lesen.

Codebeispiel auf codesandbox

im Beispiel von codesandbox mehrmals hintereinander auf die Schaltfläche „Namen mit Verzögerung abrufen“ drücken, Sie werden ein leichtes Flackern sehen.

Hier passiert Folgendes:

  1. Beim Klicken auf die Schaltfläche setzen wir den Namen auf den Zustand der Komponente, er wird in das virtuelle DOM geschrieben

  2. useEffect starten

  3. Der darin enthaltene Code wird in eine asynchrone Warteschlange verschoben

  4. js vervollständigt alle Operationen, die sich in der Aufrufliste befinden (hello Event-Schleife), einschließlich der Anzeige für den Benutzer, was wir in den Zustand der Komponente geschrieben haben, wenn die Schaltfläche gedrückt wird.

  5. Nachdem der Callstack leer ist, gehen wir in die Queue, in der unser Callback von useEffect liegt

  6. Wir führen es aus, der virtuelle Baum ändert sich

  7. Was wir im Status innerhalb dieses Callbacks setzen, ist bereits gerendert.

useLayoutEffect, anstatt einen Rückruf an eine asynchrone Warteschlange zu senden, führt den Code sofort aus, oder besser gesagt, nicht ganz sofort, zuerst führt es setState von der Schaltfläche aus, es gibt eine Änderung im virtuellen Stammbaum, danach führt es useLayoutEffect aus, aber anders als useEffect verschiebt es den Callback nicht in die asynchrone Call-Queue, sondern führt ihn sofort aus, der virtuelle DOM-Baum ändert sich erneut und danach wird der reale Browser-Baum neu gerendert. Versuchen Sie, schnell auf die Schaltfläche “Namen ohne Verzögerung abrufen” zu drücken, Sie werden kein Blinken sehen.

Seien Sie vorsichtig mit 0, wenn Sie auf Rendering prüfen

Zum Schluss noch eine kleine Warnung. In normalem JS-Code führen wir häufig diese Überprüfung durch:

if(arr.length) { //Wenn die Array-Länge !== 0 ist, arbeite mit Array-Elementen arr.map((item) => { //dein Code }) }

Und es scheint logisch, die gleiche Überprüfung in der Renderkomponente durchzuführen:

items.length && items.map((item) =>

{item}

)

Aber die Reaktion wird in diesem Fall nicht so funktionieren, wie wir es erwarten. Wenn die Länge des Arrays größer als Null ist, dann ist alles in Ordnung, wir werden das Array durchlaufen und rendern, was wir brauchen, aber wenn es 0 ist, dann wird es 0 anzeigen, anstatt uns “nichts” zu rendern.

Für einen solchen Fall können Sie die folgende Prüfung verwenden:

importiere “./styles.css”; const Artikel = []; export default function App() { return (

Check array on arr.length:

{items.length && items.map((item) =>

{item }

)}

Check array on arr.length {“>”} 0:

{items.length > 0 && items.map((item) =>

{item}< /div>)}

); }

Ich hoffe, dieser Artikel war für jemanden nützlich. Wenn Sie Fehler sehen, freue ich mich, wenn Sie darüber schreiben, ich werde auf jeden Fall Korrekturen vornehmen.

Similar Posts

Leave a Reply

Your email address will not be published.