Komponensek és prop-ok

A komponensek lehetővé teszik számodra a felhasználói felület független, újrafelhasználható darabokra való felosztását, és segítenek hogy minden darabról a többitől elzártan tudj gondolkodni. Ez az oldal a komponensek lényegét mutatja be. A részletes komponens API referenciát itt találod.

Elviekben a komponensek olyanok mint a JavaScript függvények. Egy tetszőleges számú inputot fogadnak (amiket “prop”-oknak hívunk) és egy React elemet adnak vissza ami leírja mi jelenjen meg a képernyőn.

Függvény és Osztály komponensek

Egy komponens legegyszerűbb definiálásának módja egy JavaScript függvény:

function Welcome(props) {
  return <h1>Helló, {props.name}</h1>;
}

Ez a függvény egy érvényes React komponens, mivel egyetlen “props” (angol properties, vagy tulajdonságok) objektum argumentuma van ami adatot tartalmaz, és egy React elemet ad vissza. Egy ilyen komponenst hívunk “függvény komponensnek”, mert szó szerint csak egy JavaScript függvény.

Emellett használhatsz ES6 osztályokat is komponensek definiálásához:

class Welcome extends React.Component {
  render() {
    return <h1>Helló, {this.props.name}</h1>;
  }
}

A React szemszögéből a fenti két komponens egymással megegyező.

Mind a függvény-, és osztálykomponensek rendelkeznek néhány extra funkcióval, amit a következő fejezetekben beszélünk ki.

Egy komponens renderelése

Korábban csak olyan React elemekkel találkoztunk, amik csak DOM címkéket képviseltek:

const element = <div />;

Azonban az elemek képviselhetnek a felhasználó által definiált komponenseket is:

const element = <Welcome name="Sára" />;

Ha a React egy olyan elemet lát, ami egy felhasználó által definiált komponenst képvisel, akkor a JSX attribútumokat és a gyermekeket egy sima objektumként küldi le a komponensnek. Ezt az objektumot hívjuk “props”-nak.

Például ez a kód a “Helló, Sára” szöveget rendereli az oldalon:

function Welcome(props) {  return <h1>Helló, {props.name}</h1>;
}

const element = <Welcome name="Sára" />;ReactDOM.render(
  element,
  document.getElementById('root')
);

Próbáld ki a CodePen-en

Foglaljuk össze mi történik ebben a példában:

  1. Meghívjuk a ReactDOM.render() metódust a <Welcome name="Sára" /> elemmel.
  2. A React meghívja a Welcome komponenst a {name: 'Sára'} props objektummal.
  3. A Welcome komponensünk visszaadja a <h1>Helló, Sára</h1> elemet eredményként.
  4. A React DOM hatékonyan frissíti a DOM-ot hogy az megegyezzen a <h1>Helló, Sára</h1>-val.

Megjegyzés: A komponensek neveit mindig nagybetűvel kezdd.

Azokat a komponenseket amik kisbetűvel kezdődnek, a React szimpla DOM címkékként kezeli. Például a <div /> egy HTML div címkét képvisel, de a <Welcome /> egy komponenst, és szükséges, hogy a Welcome a hatókörben legyen.

Ha többet szeretnél megtudni ezen közös megegyezés mögötti érvelésről, olvasd el a JSX-ről mélyebben részt.

Komponensek komponálása

A komponensek utalhatnak más komponensekre is a kimenetükben. Ez lehetővé teszi számunkra, hogy ugyanazt a komponens absztrakciót használjuk bármilyen részletességgel. Egy gomb, egy űrlap, egy dialógus, egy képernyő: React alkalmazásokban ezek általában mind komponensként vannak kifejezve.

Például készíthetünk egy App komponenst, ami több Welcome komponenst renderel:

function Welcome(props) {
  return <h1>Helló, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Sára" />      <Welcome name="Kata" />      <Welcome name="Edit" />    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

Próbáld ki a CodePen-en

Tipikusan az új React alkalmazásoknak van egy App komponensük a legfelsőbb szinten. Azonban ha egy meglévő alkalmazásba integrálod a Reactet, dolgozhatsz lentről felfelé fokozatosan haladva, kezdve kis komponensekkel, mint egy Button amíg el nem éred a nézet hierarchia csúcsát.

Komponensek kivonása

Ne félj a komponenseket kisebb komponensekké feldarabolni.

Vedd ezt a Comment komponenst példának:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <img className="Avatar"
          src={props.author.avatarUrl}
          alt={props.author.name}
        />
        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Próbáld ki a CodePen-en

Ez fogad egy author (objektumot), text (karakterláncot), és date (dátumot) props-ként, és egy kommentet ír le egy közösségi média weblapon.

Ezt a komponenst furfangos lehet megváltoztatni a sok egymásba ágyazás miatt, és nehéz is újra felhasználni az egyedülálló részeit. Vonjunk ki egy pár komponenst belőle.

Először is kivonjuk az Avatar komponenst:

function Avatar(props) {
  return (
    <img className="Avatar"      src={props.user.avatarUrl}      alt={props.user.name}    />  );
}

Az Avatar-nak nem kell tudnia, hogy mit is renderelünk a Comment-ben. Ezért is adtunk a prop-jának egy általánosabb nevet mint a user, az author helyett.

Ajánljuk a prop-ok elnevezését a komponens saját szemszögéből nézve, a kontextus helyett amiben az használva van.

Most egy kicsit tudunk egyszerűsíteni a Comment komponensen:

function Comment(props) {
  return (
    <div className="Comment">
      <div className="UserInfo">
        <Avatar user={props.author} />        <div className="UserInfo-name">
          {props.author.name}
        </div>
      </div>
      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

A következőben kivonjuk a UserInfo komponenst ami az Avatar-t rendereli a felhasználó neve mellett:

function UserInfo(props) {
  return (
    <div className="UserInfo">      <Avatar user={props.user} />      <div className="UserInfo-name">        {props.user.name}      </div>    </div>  );
}

Ez tovább egyszerűsíti a Comment komponensünket:

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />      <div className="Comment-text">
        {props.text}
      </div>
      <div className="Comment-date">
        {formatDate(props.date)}
      </div>
    </div>
  );
}

Próbáld ki a CodePen-en

A komponensek kivonása elsőre morgós munkának tűnhet, de nagyobb alkalmazások esetén gyorsan megtérül ha egy újrafelhasználható komponens palettával rendelkezünk. Egy jó ökölszabály ha a felhasználói kezelőfelületed valamelyik része többször fel van használva (Button, Panel, Avatar), vagy elég bonyolult saját magában is (App, FeedStory, Comment) akkor jó jelölt lehet egy újrafelhasználható komponensnek.

A prop-ok csak olvashatók

Függetlenül hogy egy komponenst függvényként vagy osztályként deklarálsz, az soha nem módosíthatja annak saját prop-jait. Vedd ezt a sum függvényt:

function sum(a, b) {
  return a + b;
}

Egy ilyen függvényt “tiszta” függvénynek nevezünk, mert nem kísérli meg megváltoztatni a bemenetét, és mindig ugyanazt az eredményt adja ugyanazon bemenet esetében.

Összehasonlításképpen ez a függvény nem tiszta, mert megváltoztatja a saját bemenetét:

function withdraw(account, amount) {
  account.total -= amount;
}

A React elég rugalmas, de van egy szigorú szabálya:

Minden React komponensnek tiszta függvényként kell viselkednie annak prop-jaira tekintettel

Természetesen az alkalmazások felhasználói felületei dinamikusak és idővel változnak. A következő fejezetben bemutatunk egy új koncepciót, az állapotot, vagyis a “state”-t. A állapotok lehetővé teszik a React komponenseknek hogy idővel megváltoztassák a kimenetüket a felhasználó interakciói, hálózati válaszok, vagy bármi más esetén, anélkül, hogy ezt a szabályt megszegnénk.