Přesunutí stavu výš
Festivalová aplikace se teď skládá z komponent: nahoře je Hlavicka a pro každou kapelu jedna KartaKapely. Každá karta má tlačítko s hvězdou a ve vlastním stavu si drží, jestli je její kapela oblíbená, jak jste to viděli v lekci Stav. Teď má hlavička ukázat, kolik je oblíbených kapel. Jenže to nejde: stav je uvnitř karet a komponenta nemůže číst stav jiné komponenty. Props vedou jen jedním směrem, dolů od rodiče k jeho dětem.
Když dvě komponenty potřebují stejný stav, přesuňte ho výš, do jejich nejbližšího společného rodiče: do nejbližší komponenty, která má obě uvnitř. Tady je to App. Stav bude v App a ta každému dítěti předá v props, co potřebuje: hodnotu a funkci, která ji mění. Tomu se říká přesunout stav výš (anglicky lifting state up).
Malý příklad, se dvěma komponentami v jednom souboru: košík ukazuje koupené vstupenky a tlačítko pod ním koupí další:
import { useState } from "react";
export default function App() {
const [vstupenky, setVstupenky] = useState(0);
function kup() {
setVstupenky((vstupenky) => vstupenky + 1);
}
return (
<main>
<Kosik vstupenky={vstupenky} />
<TlacitkoKoupit onKoupit={kup} />
</main>
);
}
function Kosik({ vstupenky }) {
return <p>Vstupenky v košíku: {vstupenky}</p>;
}
function TlacitkoKoupit({ onKoupit }) {
return <button onClick={onKoupit}>Koupit vstupenku</button>;
}TlacitkoKoupit neví, co koupení udělá. Jen zavolá onKoupit, když se na něj klikne. App rozhodne, co se stane, změní svůj stav a vykreslí se znovu, takže Kosik dostane v props nové číslo. Stav je na jednom místě a obě děti používají stejnou hodnotu.
U oblíbených kapel si App drží pole s id oblíbených kapel. Každá karta dostane dvě props: oblibena, jestli je její kapela v poli, a onPrepnoutOblibenou, funkci, která kapelu do pole přidá, nebo ji z něj odebere. Nové pole vzniká ze starého, takže ho v obou větvích vytvoří aktualizační funkce:
function prepniOblibenou(id) {
if (oblibene.includes(id)) {
setOblibene((oblibene) =>
oblibene.filter((oblibenaId) => oblibenaId !== id),
);
} else {
setOblibene((oblibene) => [...oblibene, id]);
}
}onPrepnoutOblibenou={() => prepniOblibenou(kapela.id)} dá každé kartě funkci, která už svou kapelu zná, stejně jako v lekci Události. A karta už useState nepotřebuje: ukazuje, co říkají její props, a když se klikne na hvězdu, zavolá onPrepnoutOblibenou.
Jak psát:
Pokyny
V App mějte oblíbené kapely ve stavové proměnné oblibene: v poli s id, které začíná prázdné. Každé komponentě KartaKapely předejte props oblibena a onPrepnoutOblibenou a v KartaKapely.jsx je použijte místo vlastního stavu karty.
Předejte komponentě Hlavicka počet oblíbených kapel jako pocet. Vyzkoušejte to: označte hvězdou pár kapel.