Bármilyen alkalmazásnál a kódba égetett adatoknál egy fokkal jobb megoldás az, ha az adatokat külső fájlból olvassuk be. Persze ez sem a legjobb megoldás, de egyelőre érjük be ennyivel és lassan haladjunk előre.
Tehát, ha most belenézünk az index.js-be, akkor látni, hogy a komponensekbe kézzel írtunk bele minden adatot. A nevet (name), model azonosítót (id) és a sorozatszámot (serialNumber):
<Terminator id={models[0].id} name={models[0].name} serialNumber={models[0].serialNumber} />
<Terminator id={models[1].id} name={models[1].name} serialNumber={models[1].serialNumber} />
<Terminator id={models[2].id} name={models[2].name} serialNumber={models[2].serialNumber} />
Ez már kevés adatnál sem szép, de mi van abban az esetben, ha nem csak három, hanem ezer komponens van? Eléggé kényelmetlen lenne még további 997 alkalomal lemásolni és átírni a tömb indexeket. Nem vagyunk mi robotok :).
Szóval kellene valami, ami kilistázza ezeket a komponenseket, ahelyett, hogy egyesével adjuk meg őket. Mivel a React-ben minden weboldal elemet komponensből építünk fel, a listázást is egy komponenssel fogjuk megoldani.
A TerminatorList komponens
TerminatorList-nek fogom hívni és létrehozok neki egy alkönyvtárat a components mappán belül, és egy fájlt, ami a komponens kódját tartalmazza majd:

Aztán a komponens fájlt beimportálom az index.js-be:
import TerminatorList from "./components/terminator-list/terminator-list.component";
Visszatérve a komponens fájlba (terminator-list.component.jsx) elkezdem kidolgozni a magát komponenst: importálom a React-et, létrehozom a TerminatorList nyílfüggvényt és jön a return():
import React from "react";
const TerminatorList = () => {
return(
);
}
A kérdés az, hogy a return mit adjon vissza? A válasz, hogy gyakorlatilag azt a Terminátor listát, ami jelenleg még az index.js-ben van. Onnan tehát kivágom és beillesztem a terminátor lista komponensbe (terminator-list.component.jsx):
return (
<div>
<Terminator
id={models[0].id}
name={models[0].name}
serialNumber={models[0].serialNumber}
/>
<Terminator
id={models[1].id}
name={models[1].name}
serialNumber={models[1].serialNumber}
/>
<Terminator
id={models[2].id}
name={models[2].name}
serialNumber={models[2].serialNumber}
/>
</div>
)
Ezzel csak egy baj van. Továbbra is be vannak égetve a komponensek. De ezt majd később javítom. Addig is gyorsan exportálom a komponenst, hogy máshol tudjam majd használni (importálni):
export default TerminatorList;
Most azt csinálom, ha még nem tettem volna meg korábban, hogy az index.js-ből törlöm azt a csúnya kódot, ami jelenleg benne van, és csak a TerminatorList komponenst helyezem el, így:
ReactDOM.render(
<TerminatorList />,
document.getElementById("root")
);
Máris sokkal szebb lett és rövidebb a kód. Egyúttal a Terminator komponens importálására itt már nincs szükségem. Törlöm is. Ugyanakkor importálnom kell a TerminatorList komponenst:
import TerminatorList from "./components/terminator-list/terminator-list.component";
A listázó komponensnek szüksége van az index.js-ből kitörölt Terminator komponensre. Tehát a terminator-list.component.jsx fájlba importálnom kell, hiszen az használja a Terminator komponenst.
import Terminator from "../terminator/terminator.component";
Az elérésnél ugyebár egy könyvtárat vissza kell lépnem, mert a megadás relatív ahhoz a komponenshez képest, amiben vagyok, ez pedig a listázó.
A props használata
A TerminatorList komponensnek valahogyan meg kell kapnia a megjelenítendő modellek listáját. De hogyan? Jaaa, hogy van nekünk a props, akkor át tudjuk adni a tulajdonságként:
<TerminatorList models={models} />
De szuper :)! Bár egyelőre a VSCode terminálja és a böngésző is tele van hibákkal, mert a models tömböt bár az index.js-ben átadtuk a listázó komponensnek, de abban még nem használtuk:
src\components\terminator-list\terminator-list.component.jsx Line 9:13: ‘models’ is not defined no-undef
Azt kell tegyük, hogy a listázó függvényének átadjuk paraméterként a models tömböt. Ezt a props-ból vesszük ki azzal, amit tanultunk, vagyis a destruktúrálással:
const TerminatorList = ({ models }) => {
És, ha most megnézzük a böngészőt, akkor megint látnunk kell a terminátor modelleket.

Adatok külső fájlból
Alakul a molekula. Azonban még meg kell oldanunk azt a csúnyaságot, ami a listázó komponens hasában van. Konkrétan azt, hogy oda be vannak égetve a komponensek és nem a fájlból veszi a modelleket.
Gondoljuk át logikusan! Az teljesen biztos, hogy a modellek, amiket ki akarunk olvasni, a models változóban lesznek, ami a models.js fájlból kapja az értékeit (előző lecke anyaga). Ezen a tömb változón kell végigmasírozni és ebből kiszedegetni minden lépésben egy modell adatait.
A map() tömb függvényt fogjuk erre a célra használni.
Ott tartunk, hogy a TerminatorList komponenst elkezdtük megírni:
const TerminatorList = ({ models }) => {
};
Az ő belsejében egy return utasításon belül egy <div> elem fogja tartalmazni a listát a következő módon:
const TerminatorList = ({ models }) => {
return (
<div>
</div>
);
};
Ezen belül fogjuk a map()-el kilistáztatni a kis robotokat. A komponens paramétereként kapott models tömbön fogunk végignyargalni a map() függvénnyel.
A map paraméterül egy callback függvényt vár, úgyhogy adok neki egyet, méghozzá egy nyíl függvényt:
models.map(
() => {
}
);
A nyíl függvénynek egyetlen paramétert adunk át. Az aktuális tömbelemet, amit model-nek nevezek.
(model) => {
Aztán, amivel a nyíl függvény visszatér a return utasításban az egy Terminator komponens lesz:
models.map((model) => {
return (
<Terminator
id={models[0].id}
name={models[0].name}
serialNumber={models[0].serialNumber}
/>
);
});
Amint az látható, idemásoltam az elsőt, amit anno kézzel kellett beírni. Ezt átalakítom úgy, hogy a szükséges adatok már dinamikusan érkezzenek meg:
models.map((model)=> {
return (
<Terminator
id={model.id}
name={model.name}
serialNumber={model.serialNumber}
/>
);
})
Tehát minden lépésben a map visszaad nekünk egy Terminator komponenst.
Így néz ki a listázó komponens teljes kódja:
import React from "react";
import Terminator from "../terminator/terminator.component";
const TerminatorList = ({ models }) => {
return (
<div>
{models.map((model) => {
return (
<Terminator
key={model.id}
id={model.id}
name={model.name}
serialNumber={model.serialNumber}
/>
);
})}
</div>
);
};
export default TerminatorList;
Ha jól dolgoztunk, akkor a böngészőben pedig ez jelenik meg:

A key lista-attribútum
Nagyon király ugye? De még mielőtt elkezdünk örvendezni, nézzünk bele a Chrome konzoljába:

Értem én, hogy mi a baja a React-nek. Ő azt mondja, hogy szeretné, ha minden egyes komponensnek lenne egy egyedi azonosítója, amit key-nek hívunk és ennek pedig legyen valami teljesen egyedi értéke.
Jogos, mert a key segítségével fogja a React azonosítani az egyes komponenseket. Terminátoraink esetében, ami egyedi az az id. Illetve jelenlegi esetünkben az index is. De az index kevésbé biztonságos az ilyen célra. Ezért én most az id-t fogom használni. Tehát a ciklusban ezt kell módosítani:
<Terminator
key={model.id}
id={model.id}
Vagyis megadtam neki a key tulajdonságot és értéknek a model.id-t. Már a böngészőben sincs hiba, a key megadásával sikerült a React kedvében járni.
Github
Ahol most tartunk a Githubról is letölthető.
YouTube
Aki pedig szeretné videón végignézni / hallgatni, amit eddig csináltunk, annak íme: