We want to hear from you!Take our 2021 Community Survey!
This site is no longer updated.Go to react.dev

Állapot és életciklus

These docs are old and won’t be updated. Go to react.dev for the new React docs.

These new documentation pages teach modern React and include live examples:

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 root.render() metódus meghívásával megváltoztatjuk a renderelt kimenetet:

const root = ReactDOM.createRoot(document.getElementById('root'));
  
function tick() {
  const element = (
    <div>
      <h1>Helló, világ!</h1>
      <h2>Az idő {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  root.render(element);}

setInterval(tick, 1000);

Próbáld ki a CodePen-en

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:

const root = ReactDOM.createRoot(document.getElementById('root'));

function Clock(props) {
  return (
    <div>      <h1>Helló, világ!</h1>      <h2>Az idő {props.date.toLocaleTimeString()}.</h2>    </div>  );
}

function tick() {
  root.render(<Clock date={new Date()} />);}

setInterval(tick, 1000);

Próbáld ki a CodePen-en

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:

root.render(<Clock />);

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:

  1. Készíts egy ES6 osztályt ugyanazzal a névvel és terjeszd ki a React.Component osztályt.
  2. Adj hozzá egy üres render() metódust.
  3. Helyezd át a a függvény testét a render() metódusba.
  4. Nevezd át a props-ot this.props-ra a render() testében.
  5. Töröld a megmaradt üres függvény deklarációt.
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Helló, világ!</h1>
        <h2>Az idő {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Próbáld ki a CodePen-en

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:

  1. Nevezd át a this.props.date-et this.state.date-re a render() metódusban:
class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Helló, világ!</h1>
        <h2>Az idő {this.state.date.toLocaleTimeString()}.</h2>      </div>
    );
  }
}
  1. Adj hozzá egy osztály konstruktort, ami hozzárendel egy kezdetleges this.state-et:
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};  }

  render() {
    return (
      <div>
        <h1>Helló, világ!</h1>
        <h2>Az idő {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

Figyeld meg, hogy hogyan adjuk át az alapkonstruktornak a props-ot:

  constructor(props) {
    super(props);    this.state = {date: new Date()};
  }

Az osztálykomponensek konstruktorai mindig meg kell hogy hívják az alapkonstruktort a props átadásával.

  1. Töröld ki a date prop-ot a <Clock /> elemből:
root.render(<Clock />);

Az időzítő kódját később adjuk vissza a komponensbe.

Az eredmény így néz ki:

class Clock extends React.Component {
  constructor(props) {    super(props);    this.state = {date: new Date()};  }
  render() {
    return (
      <div>
        <h1>Helló, világ!</h1>
        <h2>Az idő {this.state.date.toLocaleTimeString()}.</h2>      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock />);

Próbáld ki a CodePen-en

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:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {  }
  componentWillUnmount() {  }
  render() {
    return (
      <div>
        <h1>Helló, világ!</h1>
        <h2>Az idő {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

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:

  componentDidMount() {
    this.timerID = setInterval(      () => this.tick(),      1000    );  }

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:

  componentWillUnmount() {
    clearInterval(this.timerID);  }

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.

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      1000
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {    this.setState({      date: new Date()    });  }
  render() {
    return (
      <div>
        <h1>Helló, világ!</h1>
        <h2>Az idő {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Clock />);

Próbáld ki a CodePen-en

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:

  1. Amikor a <Clock />-ot átadjuk a root.render() metódusnak, a React meghívja a Clock komponens konstruktorát. Mivel a Clock komponensnek meg kell jelenítenie a jelenlegi időt, ez inicializál egy this.state-et, ami egy objektumot tartalmaz a jelenlegi idővel. Később ezt az állapotot frissítjük.
  2. Ezután a React meghívja a Clock komponens render() 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 a Clock render kimenetével.
  3. Amikor a Clock kimenet be van illesztve a DOM-ba, a React meghívja a componentDidMount() életciklus metódust. Ezen belül a Clock 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 komponens tick() metódusát.
  4. A böngésző minden másodpercben meghívja a tick() metódust. Ezen belül, a Clock komponens beütemez egy kezelői felület frissítést a setState() meghívásával egy objektummal, ami a jelenlegi időt tartalmazza. A setState() hívásnak köszönhetően a React tudja, hogy az állapot megváltozott, és újra meghívja a render() metódust, hogy megtudja, minek kéne megjelennie a képernyőn. Ezúttal a this.state.date a render() 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.
  5. Ha a Clock komponens el lesz távolítva a DOM-ból, a React meghívja a componentWillUnmount() é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:

// Helytelen
this.state.comment = 'Helló';

Használd helyette a setState()-t:

// Helyes
this.setState({comment: 'Helló'});

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:

// Helytelen
this.setState({
  counter: this.state.counter + this.props.increment,
});

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:

// Helyes
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));

A fentiekben egy nyíl függvényt használtunk, de ez működne egy átlagos függvénnyel is:

// Helyes
this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  };
});

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:

  constructor(props) {
    super(props);
    this.state = {
      posts: [],      comments: []    };
  }

Ezek aztán függetlenül frissíthetőek különálló setState() hívásokkal:

  componentDidMount() {
    fetchPosts().then(response => {
      this.setState({
        posts: response.posts      });
    });

    fetchComments().then(response => {
      this.setState({
        comments: response.comments      });
    });
  }

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:

<FormattedDate date={this.state.date} />

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:

function FormattedDate(props) {
  return <h2>Az idő {props.date.toLocaleTimeString()}.</h2>;
}

Próbáld ki a CodePen-en

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:

function App() {
  return (
    <div>
      <Clock />      <Clock />      <Clock />    </div>
  );
}

Próbáld ki a CodePen-en

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.

Hasznos volt ez az oldal?Az oldal szerkesztése