Sie haben mehrere Komponenten mit
Hooks geschrieben . Vielleicht - sie haben sogar eine kleine Anwendung erstellt. Im Allgemeinen sind Sie mit dem Ergebnis sehr zufrieden. Sie sind an die API gewöhnt und haben dabei einige unbekannte nĂŒtzliche Tricks gefunden. Sie haben sogar einige
Ihrer eigenen Hooks erstellt und Ihren Code auf 300 Zeilen reduziert, indem Sie das eingefĂŒgt haben, was zuvor durch Wiederholen von Programmfragmenten dargestellt wurde. Was Sie getan haben, haben Sie Kollegen gezeigt. "Gut gemacht", sagten sie ĂŒber Ihr Projekt.

Aber manchmal, wenn Sie
useEffect
verwenden,
useEffect
die Komponenten der Softwaremechanismen nicht sehr gut zusammen. Es scheint dir, dass dir etwas fehlt. All dies Àhnelt der Arbeit mit klassenbasierten Komponentenlebenszyklusereignissen ... aber ist es wirklich so?
Wenn Sie versuchen zu verstehen, was genau nicht zu Ihnen passt, stellen Sie fest, dass Sie die folgenden Fragen stellen:
- Wie spiele
useEffect
componentDidMount
mit useEffect
? - Wie lade
useEffect
Daten in useEffect
? Was ist []
? - MĂŒssen Funktionen als EffektabhĂ€ngigkeiten angegeben werden?
- Warum gerÀt ein Programm manchmal in eine Endlosschleife zum erneuten Laden von Daten?
- Warum ist der alte Zustand manchmal in den Effekten sichtbar oder werden alte Eigenschaften gefunden?
Als ich anfing, Haken zu benutzen, quĂ€lten mich diese Fragen auch. Selbst als ich die Dokumentation vorbereitete, konnte ich nicht sagen, dass ich einige Feinheiten perfekt beherrsche. Seitdem hatte ich einige Momente, in denen ich plötzlich etwas Wichtiges erkannte und wirklich ausrufen wollte: "Eureka!" Ăber das, was ich in diesen Momenten realisiert habe, möchte ich Ihnen erzĂ€hlen. Was Sie jetzt ĂŒber
useEffect
lernen, ermöglicht es Ihnen, die offensichtlichen Antworten auf die oben genannten Fragen klar zu sehen.
Aber um die Antworten auf diese Fragen zu sehen, mĂŒssen wir zuerst einen Schritt zurĂŒcktreten. Der Zweck dieses Artikels besteht nicht darin, seinen Lesern schrittweise Anweisungen fĂŒr die Arbeit mit
useEffect
. Es soll Ihnen
useEffect
helfen,
useEffect
"
useEffect
". Und ehrlich gesagt gibt es nicht viel zu lernen. TatsÀchlich werden wir die meiste Zeit damit verbringen, das zu vergessen, was wir vorher wussten.
Alles in meinem Kopf kam erst zusammen, nachdem ich aufgehört hatte, den
useEffect
Haken durch das Prisma der bekannten Methoden des Lebenszyklus komponentenbasierter Komponenten zu betrachten.
"Du musst vergessen, was dir beigebracht wurde"
habr.com/ru/company/ruvds/blog/445276/YodaEs wird davon ausgegangen, dass der Leser dieses Materials mit der
useEffect- API einigermaĂen vertraut ist. Dies ist ein ziemlich langer Artikel, der mit einem kleinen Buch verglichen werden kann. Tatsache ist, dass ich es vorziehe, meine Gedanken auf diese Weise auszudrĂŒcken. Im Folgenden werden ganz kurz Antworten auf die oben diskutierten Fragen gegeben. Vielleicht sind sie nĂŒtzlich fĂŒr diejenigen, die nicht die Zeit oder den Wunsch haben, das gesamte Material zu lesen.
Wenn das Format, in dem wir
useEffect
mit all seinen ErklĂ€rungen und Beispielen betrachten werden, fĂŒr Sie nicht sehr geeignet ist, können Sie etwas warten - bis zu dem Moment, an dem diese ErklĂ€rungen in unzĂ€hligen anderen HandbĂŒchern erscheinen. Hier ist die gleiche Geschichte wie bei der React-Bibliothek selbst, die 2013 etwas völlig Neues war. Es dauert einige Zeit, bis die Entwicklergemeinschaft das neue mentale Modell erkennt und Lehrmaterialien auf der Grundlage dieses Modells erscheinen.
Antworten auf Fragen
Hier finden Sie kurze Antworten auf die am Anfang dieses Materials gestellten Fragen, die fĂŒr diejenigen gedacht sind, die nicht den gesamten Text lesen möchten. Wenn Sie beim Lesen dieser Antworten das GefĂŒhl haben, die Bedeutung des Gelesenen nicht wirklich zu verstehen, lesen Sie das Material durch. Detaillierte ErlĂ€uterungen finden Sie im Text. Wenn Sie alles lesen möchten, können Sie diesen Abschnitt ĂŒberspringen.
âWie wird componentDidMount mit useEffect abgespielt?
Obwohl Sie das
useEffect(fn, [])
verwenden können, um die FunktionalitÀt von
componentDidMount
abzuspielen, entspricht es nicht genau der
componentDidMount
. Im Gegensatz zu
componentDidMount
erfasst es nĂ€mlich Eigenschaften und Status. Daher sehen Sie auch innerhalb des RĂŒckrufs die anfĂ€nglichen Eigenschaften und den Status. Wenn Sie die neueste Version von etwas sehen möchten, können Sie es in den
ref
Link schreiben. Normalerweise gibt es jedoch eine einfachere Möglichkeit, den Code zu strukturieren. Dies ist daher optional. Denken Sie daran, dass sich das Modell fĂŒr mentale Effekte von dem fĂŒr
componentDidMount
und andere Methoden des Komponentenlebenszyklus geltenden Modell unterscheidet. Daher kann der Versuch, die genauen Ăquivalente zu finden, mehr schaden als nĂŒtzen. Um produktiv zu arbeiten, muss man sozusagen "in Effekten denken". Die Grundlage ihres mentalen Modells liegt nĂ€her an der Implementierung der Synchronisation als an der Reaktion auf Ereignisse im Lebenszyklus von Komponenten.
âWie werden Daten in useEffect ordnungsgemÀà geladen? Was []?
Hier finden Sie eine gute Anleitung zum Laden von Daten mit
useEffect
. Versuchen Sie es vollstĂ€ndig zu lesen! Es ist nicht so groĂ. Die Klammern
[]
, die ein leeres Array darstellen, bedeuten, dass der Effekt nicht die Werte verwendet, die am React-Datenstrom beteiligt sind, und aus diesem Grund kann seine einmalige Verwendung als sicher angesehen werden. DarĂŒber hinaus ist die Verwendung eines leeren Arrays von AbhĂ€ngigkeiten eine hĂ€ufige Fehlerquelle fĂŒr den Fall, dass tatsĂ€chlich ein bestimmter Wert fĂŒr den Effekt verwendet wird. Sie mĂŒssen mehrere Strategien beherrschen (hauptsĂ€chlich in Form von
useReducer
und
useCallback
), mit denen Sie die Notwendigkeit einer AbhÀngigkeit beseitigen können, anstatt diese AbhÀngigkeit unangemessen zu verwerfen.
â MĂŒssen Funktionen als EffektabhĂ€ngigkeiten angegeben werden?
Es wird empfohlen, Funktionen, fĂŒr die keine Eigenschaften oder ein Status erforderlich sind, auĂerhalb der Komponenten zu verwenden. Es wird empfohlen, Funktionen, die nur von Effekten verwendet werden, innerhalb der Effekte zu platzieren. Wenn Ihr Effekt danach weiterhin Funktionen verwendet, die sich im Bereich des
useCallback
befinden (einschlieĂlich Funktionen aus den Eigenschaften), schlieĂen Sie sie in
useCallback
wo sie deklariert sind, und versuchen Sie, sie erneut zu verwenden. Warum ist das wichtig? Funktionen können Werte aus Eigenschaften und Status âsehenâ, sodass sie am Datenstrom teilnehmen. Weitere Informationen hierzu finden Sie in unseren FAQ.
â Warum gerĂ€t ein Programm manchmal in eine Endlosschleife zum erneuten Laden von Daten?
Dies kann passieren, wenn das Laden von Daten in einem Effekt ausgefĂŒhrt wird, der kein zweites Argument enthĂ€lt, das die AbhĂ€ngigkeiten darstellt. Ohne diese Option werden nach jedem Rendering-Vorgang Effekte ausgefĂŒhrt. Wenn Sie also den Status festlegen, werden solche Effekte abgerufen. Eine Endlosschleife kann auch auftreten, wenn im AbhĂ€ngigkeitsarray ein Wert angezeigt wird, der sich stĂ€ndig Ă€ndert. Finden Sie heraus, welche Art von Wert möglich ist, indem Sie AbhĂ€ngigkeiten einzeln entfernen. Das Entfernen von AbhĂ€ngigkeiten (oder die vorschnelle Verwendung von
[]
) ist jedoch normalerweise der falsche Ansatz zur Lösung eines Problems. Stattdessen sollten Sie die Ursache des Problems finden und es wirklich lösen. Beispielsweise können Funktionen ein Àhnliches Problem verursachen. Sie können zur Lösung beitragen, indem Sie sie in Effekte
useCallback
auĂerhalb der Komponenten verschieben oder in
useCallback
. Um das Erstellen mehrerer Objekte zu vermeiden, können Sie
useMemo
.
â Warum ist manchmal der alte Zustand in den Effekten sichtbar oder werden alte Eigenschaften gefunden?
Effekte "sehen" immer Eigenschaften und Status aus dem Rendering, in dem sie deklariert sind. Dies hilft
, Fehler zu
vermeiden , kann jedoch in einigen FÀllen den normalen Betrieb der Komponente beeintrÀchtigen. In solchen FÀllen können Sie verÀnderbare
ref
explizit verwenden, um mit solchen Werten zu arbeiten (Sie können dies am Ende des oben genannten Artikels lesen). Wenn Sie der Meinung sind, dass Sie Eigenschaften oder den Status des alten Renderings sehen, dies jedoch nicht erwarten, haben Sie möglicherweise einige AbhĂ€ngigkeiten ĂŒbersehen. Verwenden Sie
diese Linter-Regel, um zu lernen, sie zu sehen. In ein paar Tagen wird es so etwas wie Ihre zweite Natur. Schauen Sie sich auch
diese Antwort in unseren FAQ an.
Ich hoffe, diese Antworten auf die Fragen waren fĂŒr diejenigen, die sie lesen, nĂŒtzlich. Lassen Sie uns nun mehr ĂŒber
useEffect
sprechen.
Jeder Render hat seine eigenen Eigenschaften und seinen eigenen Status.
Bevor wir die Effekte diskutieren können, mĂŒssen wir ĂŒber das Rendern sprechen.
Hier ist die funktionale ZĂ€hlerkomponente.
function Counter() { const [count, setCount] = useState(0); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Schauen
<p>You clicked {count} times</p>
. Was meint sie Beobachtet die konstante Konstante irgendwie Ănderungen im Zustand und wird sie automatisch aktualisiert? Diese Schlussfolgerung kann als eine Art wertvolle erste Idee von jemandem angesehen werden, der React studiert, aber es ist kein
genaues mentales Modell dessen, was passiert.
In unserem Beispiel ist
count
nur eine Zahl. Dies ist keine Art von magischer âDatenbindungâ, keine Art von âBeobachterobjektâ oder âProxyâ oder irgendetwas anderes. Vor uns liegt eine alte gute Nummer wie diese:
const count = 42;
WĂ€hrend der ersten Komponentenausgabe ist der von
useState()
erhaltene
useState()
0. Wenn wir
setCount(1)
aufrufen, ruft React die Komponente erneut auf. Diese
count
ist 1. Und so weiter:
React ruft die Komponente auf, wenn wir den Status aktualisieren. Infolgedessen "sieht" jede Rendering-Operation ihren eigenen Wert des
counter
, der innerhalb der Funktion eine Konstante ist.
Infolgedessen fĂŒhrt diese Zeile keine spezielle Datenbindungsoperation aus:
<p>You clicked {count} times</p>
Es wird nur ein numerischer Wert in den Code eingebettet, der beim Rendern generiert wird. Diese Nummer wird von React bereitgestellt. Wenn wir
setCount
, ruft React die Komponente erneut mit einem anderen
count
. React aktualisiert dann das DOM, sodass das Dokumentobjektmodell mit der neuesten Datenausgabe beim Rendern von Komponenten ĂŒbereinstimmt.
Die wichtigste Schlussfolgerung, die daraus gezogen werden kann, ist, dass die
count
eine Konstante innerhalb eines bestimmten Renderings ist und sich im Laufe der Zeit nicht Àndert. Die Komponente, die immer wieder aufgerufen wird, Àndert sich. Jedes Rendern "sieht" seinen eigenen
count
, der fĂŒr jede der RendervorgĂ€nge isoliert ist.
In
diesem Material finden Sie Details zu diesem Prozess.
Jeder Render hat seine eigenen Ereignishandler.
Alles ist noch klar. Was ist mit Event-Handlern?
Schauen Sie sich dieses Beispiel an. Hier wird drei Sekunden nach dem Klicken auf die SchaltflÀche ein Meldungsfeld mit Informationen zu dem in
count
gespeicherten Wert angezeigt:
function Counter() { const [count, setCount] = useState(0); function handleAlertClick() { setTimeout(() => { alert('You clicked on: ' + count); }, 3000); } return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> <button onClick={handleAlertClick}> Show alert </button> </div> ); }
Angenommen, ich fĂŒhre die folgende Abfolge von Aktionen aus:
- Ich werde den Wert von
count
auf 3 bringen, indem Click me
SchaltflÀche " Click me
klicke. - Klicken Sie auf die SchaltflÀche
Show alert
anzeigen. - Erhöhen Sie den Wert vor Ablauf des Zeitlimits auf 5.
Erhöhen des ZÀhlwerts nach Klicken auf die SchaltflÀche Benachrichtigung anzeigenWas erscheint Ihrer Meinung nach im Meldungsfeld? Wird dort 5 angezeigt, was dem
count
zum Zeitpunkt des Auslösens des Timers entspricht, oder 3 - also der
count
zum Zeitpunkt des Tastendrucks?
Jetzt finden Sie die Antwort auf diese Frage. Wenn Sie jedoch alles selbst herausfinden möchten, finden Sie
hier eine funktionierende Version dieses Beispiels.
Wenn Ihnen das, was Sie gesehen haben, unverstÀndlich erscheint, finden Sie hier ein Beispiel, das der RealitÀt nÀher kommt. Stellen Sie sich eine Chat-Anwendung vor, in der im Status die
ID
aktuellen EmpfÀngers der Nachricht gespeichert ist und eine SchaltflÀche zum
Send
vorhanden ist. In
diesem Material wird das Geschehen im Detail betrachtet. TatsÀchlich lautet die richtige Antwort auf die Frage, was im Meldungsfeld angezeigt wird, 3.
Der Mechanismus zum Anzeigen eines Meldungsfelds hat den Status zum Zeitpunkt des Klickens auf die SchaltflĂ€che âerfasstâ.
Es gibt Möglichkeiten, eine andere Version des Verhaltens zu implementieren, aber im Moment werden wir uns mit dem Standardverhalten des Systems befassen. Beim Aufbau mentaler Technologiemodelle ist es wichtig, den "Weg des geringsten Widerstands" von allen Arten von "NotausgÀngen" zu unterscheiden.
Wie funktioniert das alles?
Wir haben bereits gesagt, dass der Wert von
count
eine Konstante fĂŒr jeden spezifischen Aufruf unserer Funktion ist. Ich denke, es lohnt sich, nĂ€her darauf einzugehen. Der Punkt ist, dass unsere Funktion viele Male aufgerufen wird (einmal fĂŒr jede Renderoperation), aber bei jedem dieser Aufrufe ist die
count
darin eine Konstante. Diese Konstante wird auf einen bestimmten Wert gesetzt (der den Status einer bestimmten Renderoperation darstellt).
Dieses Verhalten von Funktionen ist nichts Besonderes fĂŒr React - gewöhnliche Funktionen verhalten sich Ă€hnlich:
function sayHi(person) { const name = person.name; setTimeout(() => { alert('Hello, ' + name); }, 3000); } let someone = {name: 'Dan'}; sayHi(someone); someone = {name: 'Yuzhi'}; sayHi(someone); someone = {name: 'Dominic'}; sayHi(someone);
In
diesem Beispiel wird die externe Variable
someone
mehrmals neu zugewiesen. Dasselbe kann irgendwo in React passieren, der aktuelle Status der Komponente kann sich Àndern. Innerhalb der
sayHi
Funktion gibt es jedoch einen lokalen Konstantennamen, der der
person
eines bestimmten Anrufs zugeordnet ist. Diese Konstante ist lokal, daher sind ihre Werte in verschiedenen Funktionsaufrufen voneinander isoliert! Infolgedessen âmerktâ sich jedes angezeigte Nachrichtenfenster nach einer ZeitĂŒberschreitung seinen eigenen
name
.
Dies erklÀrt, wie unser Ereignishandler den
count
erfasst, wenn auf eine SchaltflÀche geklickt wird. Wenn wir bei der Arbeit mit Komponenten dasselbe Prinzip anwenden, stellt sich heraus, dass jedes Rendering seinen eigenen
count
âsiehtâ:
Infolgedessen gibt jedes Rendering tatsÀchlich seine eigene "Version"
handleAlertClick
. Jede dieser Versionen "merkt" sich ihren eigenen
count
:
Aus diesem Grund gehören in
diesem Beispiel Ereignishandler zu bestimmten Renderings. Wenn Sie auf die SchaltflÀche klicken, verwendet die Komponente den
count
dieser Renderings.
Innerhalb eines bestimmten Renderings bleiben die Eigenschaften und der Status immer gleich. Wenn jedoch verschiedene Rendering-VorgĂ€nge ihre eigenen Eigenschaften und ihren eigenen Status verwenden, geschieht dasselbe mit allen Mechanismen, die sie verwenden (einschlieĂlich Ereignishandlern). Sie "gehören" auch zu bestimmten Renderings. Daher sehen selbst asynchrone Funktionen in Ereignishandlern dieselben
count
.
Es ist zu beachten, dass ich im obigen Beispiel die spezifischen
count
direkt in die
handleAlertClick
Funktion eingebettet
handleAlertClick
. Dieser "mentale" Ersatz wird uns nicht schaden, da die konstante
count
innerhalb eines bestimmten Renderings nicht geĂ€ndert werden kann. Erstens ist es eine Konstante und zweitens ist es eine Zahl. Man kann mit Sicherheit sagen, dass man auch ĂŒber andere Bedeutungen wie Objekte nachdenken kann, aber nur, wenn wir in der Regel akzeptieren, keine Ănderungen (Mutationen) im Zustand vorzunehmen. Gleichzeitig sind wir mit dem Aufruf von
setSomething(newObj)
mit einem neuen Objekt zufrieden, anstatt das vorhandene zu Ă€ndern, da bei diesem Ansatz der Status des vorherigen Renderings unberĂŒhrt bleibt.
Jeder Render hat seine eigenen Effekte.
Wie Sie wissen, ist dieses Material den Effekten gewidmet, aber wir haben noch nicht einmal darĂŒber gesprochen. Jetzt werden wir es beheben. Wie sich herausstellt, unterscheidet sich die Arbeit mit Effekten nicht besonders von dem, was wir bereits herausgefunden haben.
Betrachten Sie
ein Beispiel aus der Dokumentation, das dem bereits analysierten sehr Àhnlich ist:
function Counter() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
Jetzt habe ich eine Frage an Sie. Wie liest ein Effekt den letzten
count
?
Vielleicht wird hier eine "Datenbindung" verwendet oder ein "Beobachterobjekt", das den
count
innerhalb der Effektfunktion aktualisiert? Vielleicht ist
count
eine verÀnderbare Variable, deren Wert React in unserer Komponente festlegt, wodurch der Effekt immer die neueste Version sieht?
Nein.
Wir wissen bereits, dass beim Rendern einer bestimmten Komponente die
count
eine Konstante ist. Sogar Ereignishandler "sehen" den
count
aus dem Rendering, zu dem sie "gehören", da
count
eine Konstante ist, die sich in einem bestimmten Bereich befindet. Gleiches gilt fĂŒr Effekte!
Und es sollte beachtet werden, dass dies nicht die
count
der Variablen ist
count
die sich innerhalb des "unverÀnderten" Effekts irgendwie Àndert. Vor uns liegt die Funktion des Effekts selbst, die bei jedem Rendering-Vorgang unterschiedlich ist.
Jede Version "sieht" den
count
aus dem Render, zu dem sie "gehört":
React , DOM .
, ( ), , , , «» , «».
, , .
, ( ,
). , , , .
, , :
React:
:
- :
<p>You clicked 0 times</p>
. - , , :
() => { document.title = 'You clicked 0 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 0 times' }
.
, . , , - :
:
React:
:
- :
<p>You clicked 1 times</p>
. - , , :
() => { document.title = 'You clicked 1 times' }
.
React:
:
React:
- , , .
() => { document.title = 'You clicked 1 times' }
.
âŠ
, , , , «» .
. :
function Counter() { const [count, setCount] = useState(0); useEffect(() => { setTimeout(() => { console.log(`You clicked ${count} times`); }, 3000); }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
, ?
, . , , , . ! , , , , ,
count
.
.
: «, ! ?».
, ,
this.setState
, , . , ,
, , , :
componentDidUpdate() { setTimeout(() => { console.log(`You clicked ${this.state.count} times`); }, 3000); }
,
this.state.count
count
, , . , , , 5 , 5 .
, JavaScript-, , ,
, ,
setTimeout
, . , (React
this.state
, ), .
â , , «» , . , , , . , , . , , , , , ,
.
, ( , , - API ) , .
:
function Example(props) { useEffect(() => { setTimeout(() => { console.log(props.counter); }, 1000); });
, «» . ! . , .
, , - , , , , . ,
ref
,
.
, , , , , . , ( ), «» React-. , , . , .
, , , :
function Example() { const [count, setCount] = useState(0); const latestCount = useRef(count); useEffect(() => {
- React . React
this.state
. , ,
latestCount.current
. , . , , , .
?
, . , , «» .
:
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.id, handleStatusChange); }; });
,
props
â
{id: 10}
,
{id: 20}
â . , :
- React
{id: 10}
. - React
{id: 20}
. - React
{id: 20}
.
( , , .)
, «» - , , «» - , . â , , , . .
React
, . , . . . :
- React
{id: 20}
. - .
{id: 20}
. - React
{id: 10}
. - React
{id: 20}
.
, «»
props
,
{id: 10}
, ,
props
{id: 20}
.
, âŠ
â ?: « ( , , - API ) , ».
! « » , . , , :
, , ⊠, «» , -,
{id: 10}
.
React . , , .
props
, .
,
React , .
.
, :
function Greeting({ name }) { return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
,
<Greeting name="Dan" />
, â
<Greeting name="Yuzhi" />
,
<Greeting name="Yuzhi" />
.
Hello, Yuzhi
.
, , . React, . , , .
$.addClass
$.removeClass
jQuery- ( â , «»), , CSS- React ( â , «»).
React DOM , . «» «».
.
useEffect
, React, .
function Greeting({ name }) { useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} </h1> ); }
useEffect
, , . , - , ! , «», «».
,
A
,
B
, â
C
, ,
C
. (, - ), .
, , , . ( ).
Wie gehe ich damit um?
React
React DOM. DOM , React DOM, - .
, :
<h1 className="Greeting"> Hello, Dan </h1>
:
<h1 className="Greeting"> Hello, Yuzhi </h1>
React :
const oldProps = {className: 'Greeting', children: 'Hello, Dan'}; const newProps = {className: 'Greeting', children: 'Hello, Yuzhi'};
React ,
children
, DOM. ,
className
. :
domNode.innerText = 'Hello, Yuzhi';
- ? , , .
, , - :
function Greeting({ name }) { const [counter, setCounter] = useState(0); useEffect(() => { document.title = 'Hello, ' + name; }); return ( <h1 className="Greeting"> Hello, {name} <button onClick={() => setCounter(counter + 1)}> Increment </button> </h1> ); }
counter
.
document.title
name
,
name
.
document.title
counter
, .
React ⊠?
let oldEffect = () => { document.title = 'Hello, Dan'; }; let newEffect = () => { document.title = 'Hello, Dan'; };
â . React , , . ( .
name
.)
, , (
deps
),
useEffect
:
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
, React: «, , , ,
name
».
, , React :
const oldEffect = () => { document.title = 'Hello, Dan'; }; const oldDeps = ['Dan']; const newEffect = () => { document.title = 'Hello, Dan'; }; const newDeps = ['Dan'];
, , ! - - .
React
React â . , , , ,
useEffect
, , , . ( !)
function SearchResults() { async function fetchData() {
FAQ , . .
« !», â . : , , . , , , â , .
, , . , , , , . , . .
, , .
, React
, , React , .
useEffect(() => { document.title = 'Hello, ' + name; }, [name]);
â, , ,
[]
, , , , :
useEffect(() => { document.title = 'Hello, ' + name; }, []);
â. , «» , , .
, , , . , : «
setInterval
clearInterval
».
. , , ,
useEffect
, , ,
[]
. - , ?
function Counter() { const [count, setCount] = useState(0); useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, []); return <h1>{count}</h1>; }
, ,
.
, « , », . , , ,
setInterval
, . , ?
, â React , , . ,
count
, React , , , . â .
count
0.
setCount(count + 1)
setCount(0 + 1)
. , â
[]
,
setCount(0 + 1)
:
React, , , â .
count
â , ( ):
const count =
. React .
,. , , React , , . â
- .
React , . , , , .
, , , .
count
:
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
. , , â , .
count
,
count
,
setCount(count + 1)
:
,
setInterval
,
count
, . , .
,, , , . â , .
.
,
count
.
useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, [count]);
, ,
count
. ,
count
setCount
. , ,
count
. , ,
setState
:
useEffect(() => { const id = setInterval(() => { setCount(c => c + 1); }, 1000); return () => clearInterval(id); }, []);
« ». ,
count
- ,
setCount(count + 1)
.
count
- ,
count + 1
«» React. React
count
. , React â , , , .
setCount(c => c + 1)
. « React », , . « » , ,
.
, , , . React.
count
:
,.
,
setInterval
, ,
c => c + 1
.
count
. React .
Google Docs
, , â ? , , «», , . , Google Docs . . , .
, . . ,
setCount(c => c + 1)
, ,
setCount(count + 1)
, «»
count
. , ( â «»). « React» â
. .
( ) , Google Docs
. â , React . , , ( , , ) .
,
setCount(c => c + 1)
, . , . , , , , , .
setCount(c => c + 1)
.
useReducer
.
, :
count
step
.
setInterval
,
step
:
function Counter() { const [count, setCount] = useState(0); const [step, setStep] = useState(1); useEffect(() => { const id = setInterval(() => { setCount(c => c + step); }, 1000); return () => clearInterval(id); }, [step]); return ( <> <h1>{count}</h1> <input value={step} onChange={e => setStep(Number(e.target.value))} /> </> ); }
.
, React .
step
, . .
:
step
setInterval
â
step
. , , , ! , , , , , .
, , ,
setInterval
,
step
.
step
?
, ,
useReducer
.
,
setSomething(something => ...)
, , . «», , , .
step
dispatch
:
const [state, dispatch] = useReducer(reducer, initialState); const { count, step } = state; useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' });
.
: « , ?». , React ,
dispatch
. .
!
(
dispatch
setstate
useRef
, React , . â .)
, , , , .
step
. , . , . :
const initialState = { count: 0, step: 1, }; function reducer(state, action) { const { count, step } = state; if (action.type === 'tick') { return { count: count + step, step }; } else if (action.type === 'step') { return { count, step: action.step }; } else { throw new Error(); } }
, , , .
useReducer â -
, , , . , , ? , , API
<Counter step={1} />
. ,
props.step
?
, ! , :
function Counter({ step }) { const [count, dispatch] = useReducer(reducer, 0); function reducer(state, action) { if (action.type === 'tick') { return state + step; } else { throw new Error(); } } useEffect(() => { const id = setInterval(() => { dispatch({ type: 'tick' }); }, 1000); return () => clearInterval(id); }, [dispatch]); return <h1>{count}</h1>; }
, . , , , , .
.
dispatch
. , , . .
, , . «» , , ? ,
dispatch
, React . . .
useReducer
«-» . , . , , , , .
, - , .
, , , :
function SearchResults() { const [data, setData] = useState({ hits: [] }); async function fetchData() { const result = await axios( 'https://hn.algolia.com/api/v1/search?query=react', ); setData(result.data); } useEffect(() => { fetchData(); }, []);
, .
, , . , , , , , , , , .
, , , , :
function SearchResults() {
, , :
function SearchResults() { const [query, setQuery] = useState('react');
, (, ), . .
, . , :
function SearchResults() {
.
? , « ». React, - .
getFetchUrl
,
query
, , , , . â ,
query
:
function SearchResults() { const [query, setQuery] = useState('react'); useEffect(() => { function getFetchUrl() { return 'https://hn.algolia.com/api/v1/search?query=' + query; } async function fetchData() { const result = await axios(getFetchUrl()); setData(result.data); } fetchData(); }, [query]);
.
, « React».
query
. , , , , . , , .
exhaustive-deps
eslint-plugin-react-hooks
, . , , .
Es ist sehr bequem.
, ?
. , , . , , .
? , . : React . . , « ». , , . , , , !
, , . ,
getFetchUrl
:
function SearchResults() { function getFetchUrl(query) { return 'https://hn.algolia.com/api/v1/search?query=' + query; } useEffect(() => { const url = getFetchUrl('react');
getFetchUrl
â , .
, «» , .
getFetchUrl
(, , ), :
function SearchResults() {
,
getFetchUrl
. , â . - , , . , , , .
â .
, , :
, . , , .
. ,
useCallback :
function SearchResults() {
useCallback
. : , -, , , .
, . (
'react'
'redux'
). , , ,
query
. , ,
query
,
getFetchUrl
.
,
query
useCallback
:
function SearchResults() { const [query, setQuery] = useState('react'); const getFetchUrl = useCallback(() => {
useCallback
query
, ,
getFetchUrl
,
query
:
function SearchResults() { const [query, setQuery] = useState('react');
useCallback
,
query
,
getFetchUrl
, , .
query
,
getFetchUrl
, . Excel: - , , , .
â , . , :
function Parent() { const [query, setQuery] = useState('react');
fetchData
Parent
query
,
Child
, .
?
, , , , . , , , , :
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, : « , , ,
useEffect
â
componentDidMount
componentDidUpdate
. !».
componentDidUpdate
:
class Child extends Component { state = { data: null }; componentDidMount() { this.props.fetchData(); } componentDidUpdate(prevProps) {
,
fetchData
â ! (, , , .) - , .
this.props.fetchData
prevProps.fetchData
. , , ?
componentDidUpdate(prevProps) { this.props.fetchData(); }
. . ( .) ,
fetchData
this.state.query
?
render() { return <Child fetchData={this.fetchData.bind(this, this.state.query)} />; }
this.props.fetchData !== prevProps.fetchData
true
, ,
query
! .
, , ,
query
Child
. , ,
query
,
query
:
class Parent extends Component { state = { query: 'react' }; fetchData = () => { const url = 'https://hn.algolia.com/api/v1/search?query=' + this.state.query;
, , - , , .
, , .
this
, . , , , , - . ,
this.props.fetchData
, , , , , .
-
useCallback
. , , , . , .
useCallback
props.fetchData
.
,
useMemo
:
function ColorPicker() {
,
useCallback
, - . « », , , . , . ,
.
,
fetchData
( ), . , , . («
props.onComplete
, ?») , .
, :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . . â , :
class Article extends Component { state = { article: null }; componentDidMount() { this.fetchData(this.props.id); } componentDidUpdate(prevProps) { if (prevProps.id !== this.props.id) { this.fetchData(this.props.id); } } async fetchData(id) { const article = await API.fetchArticle(id); this.setState({ article }); }
, , , . , . ,
{id: 10}
,
{id: 20}
, , . , , , . .
, , . â , ,
async/await
( , - ) , ( , ).
,
async
-. (, , , , .)
, , ! .
, :
function Article({ id }) { const [article, setArticle] = useState(null); useEffect(() => { let didCancel = false; async function fetchData() { const article = await API.fetchArticle(id); if (!didCancel) { setArticle(article); } } fetchData(); return () => { didCancel = true; }; }, [id]);
, , , . , .
, , , , , . , , , . . â .
useEffect
, , , . React. ,
useEffect
.
, , « », . . , , , , «» , .
,
useEffect
, . â . â , , â , . , , , , API.
, ,
useFetch
, ,
useTheme
, . , ,
useEffect
. , , , .
, ,
useEffect
. â , . , . ?
Suspense React , , - ( : , , ) .
Suspense
, ,
useEffect
, , , - . , , , . , ,
, , .
Zusammenfassung
, . , , - , , , .
