Ez az oldal az állapot és életciklus fogalmait mutatja be egy React komponensben. A részletes komponens API referenciát itt találod.
Vedd a ketyegő óra példát az egyik korábbi fejezetből. Az Elemek renderelése fejezetben csak egyetlen módját tanultuk meg a felhasználói felület frissítésének. A ReactDOM.render()
metódus meghívásával megváltoztatjuk a renderelt kimenetet:
Ebben a fejezetben megtanuljuk, hogy hogyan tudjuk a Clock
komponenst igazán újrafelhasználhatóvá és egységbe foglalttá tenni. Saját időzítőt fog beállítani, hogy minden másodpercben frissíteni tudja önmagát.
Kezdhetjük azzal, hogy hogyan foglaljuk egységbe azt, ahogyan az óra kinéz:
Azonban ebből hiányzik valami nagyon fontos: Az a tény, hogy a Clock
komponens beállít egy időzítőt és minden másodpercben frissíti a felhasználói felületet, a Clock
komponens saját implementációs részlete kell hogy legyen.
Ideális esetben ezt egyszer szeretnénk megírni és hagyjuk a Clock
-ot saját magát frissíteni:
Ennek az implementálásához szükségünk lesz egy "állapot"-ra ("state") a Clock
komponensben.
Az állapot hasonló a prop-okhoz, de privát a komponensre nézve, és teljes mértékben irányított a komponens által.
Függvény konvertálása osztállyá
Egy függvény komponenst, mint például a Clock
-ot, ebben az öt lépésben tudsz osztállyá konvertálni:
- Készíts egy ES6 osztályt ugyanazzal a névvel és terjeszd ki a
React.Component
osztályt. - Adj hozzá egy üres
render()
metódust. - Helyezd át a a függvény testét a
render()
metódusba. - Nevezd át a
props
-otthis.props
-ra arender()
testében. - Töröld a megmaradt üres függvény deklarációt.
A Clock
most már osztályként van definiálva függvény helyett.
A render
metódus minden alkalommal meg lesz hívva ha egy frissítés történik, de amíg a <Clock />
-ot ugyanabba a DOM csomópontba rendereljük, addig a Clock
osztálynak csupán egy példánya lesz használva. Ez lehetővé teszi olyan funkciók hozzáadását mint a helyi állapot és életciklus metódusok.
Helyi állapot hozzáadása egy osztályhoz
Helyezzük át a date
objektumot a props-ból a state-be három lépésben:
- Nevezd át a
this.props.date
-etthis.state.date
-re arender()
metódusban:
- Adj hozzá egy osztály konstruktort, ami hozzárendel egy kezdetleges
this.state
-et:
Figyeld meg, hogy hogyan adjuk át az alapkonstruktornak a props
-ot:
Az osztálykomponensek konstruktorai mindig meg kell hogy hívják az alapkonstruktort a props
átadásával.
- Töröld ki a
date
prop-ot a<Clock />
elemből:
Az időzítő kódját később adjuk vissza a komponensbe.
Az eredmény így néz ki:
A következőben hagyjuk, hogy a Clock
maga állítson be egy időzítőt és frissítse magát minden másodpercben.
Életciklus metódusok hozzáadása egy osztályhoz
Sok komponenssel rendelkező alkalmazásokban nagyon fontos, hogy a komponensek által elfoglalt erőforrásokat felszabadítsuk, amikor azok elpusztulnak.
Szeretnénk felállítani egy időzítőt, amikor a Clock
először renderelődik DOM-ba. A Reactben ezt hívjuk "előkészítés"-nek, vagy "mounting"-nak.
Azt is szeretnénk, ha az időzítő törölve lenne, amikor a DOM által készített Clock
el lesz távolítva. A React-ben ezt hívjuk "leválasztás"-nak vagy "unmounting"-nak.
A komponens oszályban tudunk speciális metódusokat deklarálni, amik lefuttatnak egy kódot amikor a komponens előkészül, vagy leválik:
Ezeket a metódusokat "életciklus" metódusoknak" hívjuk.
A componentDidMount()
metódus azután fut le, hogy a komponens kimenete a DOM-ba lett renderelve. Ez egy jó hely az időzítő beállítására:
Vedd észre, hogy az időzítő azonosítóját közvetlenül a this
-re mentjük (this.timerID
).
Míg a this.props
-ot maga a React állítja fel, és a this.state
-nek speciális jelentése van, te nyugodtan adhatsz hozzá manuálisan egyéb mezőket, ha valamit tárolni szeretnél, ami nem vesz részt az adatfolyamban (mint például az időzítő azonosító).
Az időzítőt a componentWillUnmount()
életciklus metódusban fogjuk leállítani:
Végezetül implementálni fogunk egy tick()
metódust, amit a Clock
komponens fog futtatni minden másodpercben.
Ez a this.setState()
metódus segítségével fogja a komponens helyi állapotát frissíteni.
Az óra most már minden másodpercben kettyen.
Vegyük át gyorsan mi is történik és a metódusok milyen sorrendben vannak meghívva:
-
Amikor a
<Clock />
-ot átadjuk aReactDOM.render()
metódusnak, a React meghívja aClock
komponens konstruktorát. Mivel aClock
komponensnek meg kell jelenítenie a jelenlegi időt, ez inicializál egythis.state
-et, ami egy objektumot tartalmaz a jelenlegi idővel. Később ezt az állapotot frissítjük. -
Ezután a React meghívja a
Clock
komponensrender()
metódusát. A React ennek segítségével állapítja meg, hogy mit kell mutatnia a képernyőn. A React ezután frissíti a DOM-ot, hogy az megegyezzen aClock
render kimenetével. -
Amikor a
Clock
kimenet be van illesztve a DOM-ba, a React meghívja acomponentDidMount()
életciklus metódust. Ezen belül aClock
komponens megkéri a böngészőt, hogy az állítson fel egy időzítőt, ami minden másodpercben meghívja a komponenstick()
metódusát. -
A böngésző minden másodpercben meghívja a
tick()
metódust. Ezen belül, aClock
komponens beütemez egy kezelői felület frissítést asetState()
meghívásával egy objektummal, ami a jelenlegi időt tartalmazza. AsetState()
hívásnak köszönhetően a React tudja, hogy az állapot megváltozott, és újra meghívja arender()
metódust, hogy megtudja, minek kéne megjelennie a képernyőn. Ezúttal athis.state.date
arender()
metódusban más lesz, és ezért a render kimenete tartalmazni fogja a frissítet időt. A React ennek megfelelően frissíti a DOM-ot. -
Ha a
Clock
komponens el lesz távolítva a DOM-ból, a React meghívja acomponentWillUnmount()
életciklus metódust és az időzítő így megáll.
Az állapot helyes használata
Három dolog van, amit tudnod kell a setState()
metódusról.
Ne módosítsd az állapotot közvetlenül
Például ez nem fogja újrarenderelni a komponenst:
Használd helyette a setState()
-t:
Az egyetlen hely, ahol bármit is hozzárendelhetsz a this.state
-hez, az a konstruktor.
Az állapot frissítések lehetnek aszinkronok
A React összefoghat egy csomó setState()
hívást egy szimpla frissítésbe a teljesítmény növelése érdekében.
Mivel a this.props
és a this.state
frissülhet aszinkron módon, nem szabad az értékeikre hagyatkoznod a következő állapot kiszámításához.
Például ez a kód lehet, hogy nem fogja tudni frissíteni a számlálót:
Hogy ezt kijavítsd, használd a setState()
másik formáját, ami egy függvényt fogad argumentumként egy objektum helyett. A függvény fogadja az előző állapotot első argumentumként, valamint az előző props-ot másodikként:
A fentiekben egy nyíl függvényt használtunk, de ez működne egy átlagos függvénnyel is:
Az állapot frissítések egyesítve vannak
Amikor meghívod a setState()
metódust, a React egyesíti az általad szolgáltatott objektumot a jelenlegi állapottal.
Például az állapotod tartalmazhat számos független változót:
Ezek aztán függetlenül frissíthetőek különálló setState()
hívásokkal:
Az egyesítés sekély, tehát a this.setState({comments})
érintetlenül hagyja a this.state.posts
-ot, de teljesen lecseréli a this.state.comments
-et.
Az adat lefelé folyik
Sem a felnőtt, sem a gyermek komponens nem tudhatja, hogy egy bizonyos komponens állapotteljes vagy állapot nélküli, és az sem kell hogy érdekelje őket, hogy függvényként vagy osztályként van-e definiálva.
Ezért van az, hogy az állapotot gyakran hívjuk helyinek, vagy egységbe zártnak. Nem hozzáférhető semelyik másik komponensből, csak abból amelyik birtokolja és beállítja.
Egy komponens dönthet úgy, hogy leküldi a saját állapotát prop-ként a gyermek komponenseinek:
A FormattedDate
komponens megkapja a date
-et a props-ban, és nem tudja, hogy az a Clock állapotából, a Clock
prop-jából jött, vagy kézzel lett beírva:
Ezt közismerten "felülről lefelé irányuló", vagy egyirányú adatfolyamnak hívjuk. Egy adott állapotot mindig csak egy bizonyos komponens birtokolhat, és ez az állapot csakis a komponensfában ‘alatta lévő’ komponensek adataira vagy megjelenésére hathat.
Ha úgy képzelsz el egy komponensfát, mint a prop-ok vízesését, minden komponens állapota olyan, mint egy plusz vízforrás, ami tetszőleges pontokon belecsatlakozik a lefelé haladó áramlatba.
Hogy megmutassuk azt, hogy minden komponens tényleg teljesen izolált, készíthetünk egy App
komponenst, ami három <Clock>
-t renderel:
Minden Clock
beállítja a saját időzítőjét és ezek egymástól függetlenül frissülnek.
Az, hogy egy React komponens állapotteljes vagy állapot nélküli, a saját implementációs részletének tekinthető, ami idővel változhat. Emiatt használhatsz állapot nélküli komponenseket állapotteljes komponenseken belül, és ugyanígy fordítva is.