Подъём состояния
Приложение фестиваля теперь состоит из компонентов: вверху Header, а для каждой группы — BandCard. У каждой карточки есть кнопка-звезда, и каждая карточка хранит в своём состоянии, избранная ли её группа, как вы видели в уроке «Состояние». Теперь шапка должна показывать, сколько всего избранных групп. Но она не может: состояние лежит внутри карточек, а компонент не может прочитать состояние другого. Пропсы идут только в одну сторону — вниз, от родителя к детям.
Когда одно и то же состояние нужно двум компонентам, переместите его вверх, к их ближайшему общему родителю: ближайшему компоненту, внутри которого есть оба. Здесь это App. Состояние живёт там, а App передаёт каждому ребёнку то, что ему нужно, через пропсы: значение и функцию, которая его меняет. Это называется подъёмом состояния (по-английски lifting state up).
Небольшой пример с двумя компонентами в одном файле: корзина показывает купленные билеты, а кнопка под ней покупает ещё один:
import { useState } from "react";
export default function App() {
const [tickets, setTickets] = useState(0);
function handleBuy() {
setTickets((tickets) => tickets + 1);
}
return (
<main>
<Cart tickets={tickets} />
<BuyButton onBuy={handleBuy} />
</main>
);
}
function Cart({ tickets }) {
return <p>Билетов в корзине: {tickets}</p>;
}
function BuyButton({ onBuy }) {
return <button onClick={onBuy}>Купить билет</button>;
}BuyButton не знает, что делает покупка. Он только вызывает onBuy, когда на него нажали. Что произойдёт, решает App: он меняет своё состояние и отрисовывается заново, поэтому Cart получает в пропсах новое число. Состояние находится в одном месте, и оба ребёнка используют одно и то же значение.
Для избранного App хранит массив идентификаторов избранных групп. Каждая карточка получает два пропса: favorite — входит ли её группа в массив, и onToggleFavorite — функцию, которая добавляет группу в массив или убирает её оттуда:
function handleToggleFavorite(id) {
if (favorites.includes(id)) {
setFavorites((favorites) =>
favorites.filter((favoriteId) => favoriteId !== id),
);
} else {
setFavorites((favorites) => [...favorites, id]);
}
}onToggleFavorite={() => handleToggleFavorite(band.id)} даёт каждой карточке функцию, которая уже знает свою группу, как в уроке «События». А самой карточке useState больше не нужен: она показывает то, что говорят пропсы, и вызывает onToggleFavorite, когда нажали на звезду.
Задание
- 1
В
Appхраните избранное в переменной состоянияfavorites: массиве идентификаторов, сначала пустом. Передайте каждомуBandCardпропсыfavoriteиonToggleFavorite, а вBandCard.jsxиспользуйте их вместо собственного состояния карточки. - 2
Передайте
Headerчисло избранных групп в пропсеcount. Отметьте звёздами несколько групп, чтобы проверить.