Renderowanie list
Często zdarzy ci się wyświetlać wiele podobnych komponentów na podstawie kolekcji danych. Możesz użyć javascriptowych metod tablicowych, aby manipulować tablicą danych. Będziesz tu korzystać z filter()
i map()
w połączeniu z Reactem, aby przefiltrować i przekształcić tablicę danych w tablicę komponentów.
W tej sekcji dowiesz się
- Jak renderować komponenty z tablicy za pomocą javascriptowej funkcji
map()
. - Jak renderować tylko konkretne komponenty za pomocą javascriptowej funkcji
filter()
. - Kiedy i dlaczego stosować klucze (ang. keys) w Reakcie.
Renderowanie list z tablic
Załóżmy, że posiadasz pewną listę treści.
<ul>
<li>Creola Katherine Johnson: matematyczka</li>
<li>Mario José Molina-Pasquel Henríquez: chemik</li>
<li>Mohammad Abdus Salam: fizyk</li>
<li>Percy Lavon Julian: chemik</li>
<li>Subrahmanyan Chandrasekhar: astrofizyk</li>
</ul>
Jedyna różnica między elementami tej listy to ich treść, ich dane. Często będziesz chcieć pokazać kilka instancji tego samego komponentu, używając różnych danych podczas tworzenia interfejsów: od list komentarzy do galerii obrazków profilowych. W takich sytuacjach możesz przechowywać te dane w obiektach i tablicach javascriptowych oraz używać metod, takich jak map()
i filter()
, aby renderować na ich podstawie listy komponentów.
Oto krótki przykład, jak generować listę elementów z tablicy:
- Przenieś dane do tablicy:
const people = [
'Creola Katherine Johnson: matematyczka',
'Mario José Molina-Pasquel Henríquez: chemik',
'Mohammad Abdus Salam: fizyk',
'Percy Lavon Julian: chemik',
'Subrahmanyan Chandrasekhar: astrofizyk'
];
- Zmapuj elementy tablicy
people
na nową tablicę węzłów JSX,listItems
:
const listItems = people.map(person => <li>{person}</li>);
- Zwróć tablicę
listItems
z twojego komponentu, opakowaną w element<ul>
:
return <ul>{listItems}</ul>;
Oto rezultat:
const people = [ 'Creola Katherine Johnson: matematyczka', 'Mario José Molina-Pasquel Henríquez: chemik', 'Mohammad Abdus Salam: fizyk', 'Percy Lavon Julian: chemik', 'Subrahmanyan Chandrasekhar: astrofizyk' ]; export default function List() { const listItems = people.map(person => <li>{person}</li> ); return <ul>{listItems}</ul>; }
Zauważ, że powyższy sandbox wyświetla błąd w konsoli:
Poniżej na tej stronie dowiesz się, jak naprawić ten błąd. Zanim do tego przejdziemy, nadajmy trochę struktury twoim danym.
Filtrowanie tablicy elementów
Dane te można jeszcze bardziej ustrukturyzować.
const people = [{
id: 0,
name: 'Creola Katherine Johnson',
profession: 'matematyczka',
}, {
id: 1,
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemik',
}, {
id: 2,
name: 'Mohammad Abdus Salam',
profession: 'fizyk',
}, {
name: 'Percy Lavon Julian',
profession: 'chemik',
}, {
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrofizyk',
}];
Załóżmy, że chcesz mieć możliwość pokazywania tylko tych osób, których zawód to 'chemik'
. Możesz skorzystać z javascriptowej metody filter()
, aby zwrócić tylko takie osoby. Metoda ta przyjmuje tablicę, poddaje jej elementy “testowi” (funkcji, która zwraca true
lub false
) i zwraca nową tablicę tylko tych elementów, które zdały test (zwróciły true
).
Chcąc uzyskać tylko te elementy, gdzie profession
jest ustawione na 'chemik'
, odpowiednia funkcja “testu” powinna wyglądać tak: (person) => person.profession === 'chemik'
. Oto sposób na to, jak to wszystko połączyć w całość:
- Utwórz nową tablicę zawierającą tylko osoby o zawodzie
'chemik'
i nazwij jąchemists
. Wywołaj metodęfilter()
na tablicypeople
, filtrując według warunkuperson.profession === 'chemik'
i przypisz jej rezultat do nowo utworzonej tablicy:
const chemists = people.filter(person =>
person.profession === 'chemik'
);
- Teraz zmapuj tablicę
chemists
:
const listItems = chemists.map(person =>
<li>
<img
src={getImageUrl(person)}
alt={person.name}
/>
<p>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
{person.accomplishment}.
</p>
</li>
);
- Wreszcie zwróć
listItems
z twojego komponentu:
return <ul>{listItems}</ul>;
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const chemists = people.filter(person => person.profession === 'chemik' ); const listItems = chemists.map(person => <li> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} {person.accomplishment}. </p> </li> ); return <ul>{listItems}</ul>; }
Zachowanie kolejności elementów listy za pomocą key
(ang. klucz)
Zauważ, że wszystkie powyższe sandboxy wyświetlają błąd w konsoli:
Każdemu elementowi tablicy musisz przypisać klucz key
, czyli łańcuch znaków lub liczbę, która jednoznacznie identyfikuje go wśród innych elementów w tej tablicy:
<li key={person.id}>...</li>
Klucze key
pozwalają Reactowi zrozumieć, który komponent odpowiada któremu elementowi tablicy, dzięki czemu może je później dopasować. Jest to istotne, jeśli elementy tablicy mogą być przemieszczane (np. w wyniku sortowania), dodawane lub usuwane. Dobrze dobrany klucz key
pomaga Reactowi wywnioskować, co dokładnie się stało, i dokonać odpowiednich aktualizacji drzewa DOM.
Zamiast generować klucze dynamicznie, powinno się dołączać je do danych:
export const people = [{ id: 0, // Użyte w JSX jako klucz name: 'Creola Katherine Johnson', profession: 'matematyczka', accomplishment: 'znana z obliczeń związanych z lotami kosmicznymi', imageId: 'MK3eW3A' }, { id: 1, // Użyte w JSX jako klucz name: 'Mario José Molina-Pasquel Henríquez', profession: 'chemik', accomplishment: 'znany z odkrycia dziury ozonowej nad Arktyką', imageId: 'mynHUSa' }, { id: 2, // Użyte w JSX jako klucz name: 'Mohammad Abdus Salam', profession: 'fizyk', accomplishment: 'znany z prac nad teorią elektromagnetyzmu', imageId: 'bE7W1ji' }, { id: 3, // Użyte w JSX jako klucz name: 'Percy Lavon Julian', profession: 'chemik', accomplishment: 'znany z pionierskich prac nad lekami na bazie kortyzonu, steroidami i pigułkami antykoncepcyjnymi', imageId: 'IOjWm71' }, { id: 4, // Użyte w JSX jako klucz name: 'Subrahmanyan Chandrasekhar', profession: 'astrofizyk', accomplishment: 'znany z obliczeń masy białych karłów', imageId: 'lrWQx8l' }];
Dla dociekliwych
Co zrobić, gdy każdy element musi renderować nie jeden, ale kilka węzłów drzewa DOM?
Krótka składnia <>...</>
Fragment nie pozwala na przekazanie klucza, więc musisz albo zgrupować je w pojedynczy <div>
, albo użyć nieco dłuższej i bardziej jawnej składni <Fragment>
:
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);
Fragmenty nie pojawiają się w drzewie DOM, więc użycie ich spowoduje uzyskanie płaskiej listy elementów <h1>
, <p>
, <h1>
, <p>
i tak dalej.
Skąd wziąć klucze key
Różne źródła danych dostarczają różnych kluczy:
- Dane z bazy danych: Jeśli twoje dane pochodzą z bazy danych, możesz używać kluczy lub ID z tej bazy danych, które z natury są unikalne.
- Lokalnie generowane dane: Jeśli twoje dane są generowane i przechowywane lokalnie (np. notatki w aplikacji do robienia notatek), użyj licznika przyrostowego
crypto.randomUUID()
lub paczki takiej jakuuid
podczas tworzenia elementów.
Zasady kluczy
- Klucze muszą być unikalne między rodzeństwem. Jednakże używanie tych samych kluczy dla węzłów JSX w różnych tablicach jest jak najbardziej w porządku.
- Klucze nie mogą się zmieniać, bo to przeczy ich celowi! Nie generuj ich podczas renderowania.
Dlaczego React potrzebuje kluczy?
Wyobraź sobie, że pliki na twoim pulpicie nie mają nazw. Zamiast tego trzeba odwoływać się do nich przez ich kolejność - pierwszy plik, drugi plik i tak dalej. Można się do tego przyzwyczaić, ale gdyby usunąć plik, zaczęłoby być to kłopotliwe. Drugi plik stałby się pierwszym plikiem, trzeci plik byłby drugim plikiem i tak dalej.
Nazwy plików w folderze i klucze JSX w tablicy pełnią podobną rolę. Pozwalają nam jednoznacznie identyfikować element pośród swojego rodzeństwa. Dobrze dobrany klucz dostarcza więcej informacji niż pozycja w tablicy. Nawet jeśli pozycja zmieni się ze względu na ponowne sortowanie, klucz pozwala Reactowi identyfikować element przez cały cykl jego życia.
Powtórka
Na tej stronie nauczyliśmy cię:
- Jak przenieść dane z komponentów do struktur danych, takich jak tablice i obiekty.
- Jak generować zbiory podobnych komponentów za pomocą javascriptowej funkcji
map()
. - Jak tworzyć tablice przefiltrowanych elementów za pomocą javascriptowej funkcji
filter()
. - Jak i dlaczego ustawiać klucz
key
dla każdego komponentu w kolekcji, aby React mógł śledzić każdy z nich, nawet jeśli zmienią się ich pozycja lub dane.
Wyzwanie 1 z 4: Dzielenie listy na dwie
Ten przykład wyświetla listę wszystkich osób.
Zmień go tak, aby pokazywał dwie oddzielne listy jedna po drugiej: Chemia i Wszyscy Inni. Tak jak wcześniej, możesz określić, czy osoba jest związana z chemią, sprawdzając warunek person.profession === 'chemist'
.
import { people } from './data.js'; import { getImageUrl } from './utils.js'; export default function List() { const listItems = people.map(person => <li key={person.id}> <img src={getImageUrl(person)} alt={person.name} /> <p> <b>{person.name}:</b> {' ' + person.profession + ' '} {person.accomplishment}. </p> </li> ); return ( <article> <h1>Naukowcy</h1> <ul>{listItems}</ul> </article> ); }