К содержанию

Параметры компонентов, условия и списки

Передаем данные карточке и строим список с устойчивыми ключами.

На этой странице

Для Next.js 16.3.8 (App Router) и React 19.3.0. Обновлено .

Три карточки имеют одинаковую структуру и разные данные. Вынесем структуру в компонент, а данные передадим как props – параметры компонента. Родитель выбирает данные, дочерний компонент показывает их.

Создаем карточку

Создайте app/event-card.tsx:

app/event-card.tsx
type EventCardProps = { name: string; price: number };
 
export function EventCard({ name, price }: EventCardProps) {
  return (
    <article>
      <h2>{name}</h2>
      <p>{price === 0 ? "Бесплатно" : `${price} ₽`}</p>
    </article>
  );
}

EventCardProps описывает тип параметров карточки. { name, price } извлекает его свойства: это деструктуризация JavaScript. Props доступны для чтения; менять переданные значения внутри карточки не нужно.

В price === 0 ? ... : ... используется условное выражение. Перед ? – условие, после него – результат при true, после : – при false. В отличие от if, вся запись дает значение, которое можно вставить в JSX.

Теперь замените app/page.tsx, сохранив файл карточки:

app/page.tsx
import { EventCard } from "./event-card";
 
export default function HomePage() {
  return (
    <main>
      <h1>Куда пойти</h1>
      <EventCard name="Кинопоказ" price={300} />
      <EventCard name="Лекция" price={0} />
    </main>
  );
}

Числа передаются через { }; price="300" передал бы строку и вызвал ошибку TypeScript. Имя компонента начинается с заглавной буквы: так React отличает EventCard от встроенного элемента вроде article.

В импортах Next.js расширение .tsx можно не писать: сборщик сам найдет нужный файл. Это отличается от обычных браузерных модулей, где мы указывали .js.

Данные списком

Сохраните карточку. В page.tsx замените два ручных вызова на список:

app/page.tsx
import { EventCard } from "./event-card";
 
const events = [
  { id: 1, name: "Кинопоказ", price: 300 },
  { id: 2, name: "Лекция", price: 0 },
];
 
export default function HomePage() {
  return (
    <main>
      <h1>Куда пойти</h1>
      {events.length === 0 ? (
        <p>Пока мероприятий нет.</p>
      ) : (
        <ul>
          {events.map((event) => (
            <li key={event.id}>
              <EventCard name={event.name} price={event.price} />
            </li>
          ))}
        </ul>
      )}
    </main>
  );
}

Знакомый map возвращает JSX для каждого объекта. key указывают у внешнего элемента каждой итерации map: здесь это li. Он помогает React сохранять связь между данными и элементами при добавлении, удалении и перестановке.

Используйте постоянный id из данных. Если при каждом обновлении создавать случайный ключ, React будет считать элемент новым. Индекс массива тоже не подходит, если элементы меняют порядок. key не передается компоненту как обычный prop: если внутри нужен идентификатор, передайте id отдельно.

Содержимое через children

Вложенное содержимое передается компоненту через children. Например, простая рамка может принимать любую разметку:

app/frame.tsx
import type { ReactNode } from "react";
 
export function Frame({ children }: { children: ReactNode }) {
  return <section>{children}</section>;
}

После импорта Frame запись <Frame><p>Привет!</p></Frame> передаст абзац в children. Тип ReactNode описывает содержимое, которое React умеет отображать. Это удобно для общих оберток; для названия и цены карточки лучше явные props.

Условие без второй ветки

{isFree && <span>Бесплатно</span>} показывает метку, когда isFree равен true. С числом будьте внимательны: {events.length && <p>Есть события</p>} при пустом массиве может вывести 0. Явно сравните events.length > 0.

Попробуйте: добавьте третье событие, измените порядок, затем временно сделайте массив пустым. Для фильтра в следующей статье изменяться будет состояние, а карточки останутся теми же.

Далее – события и состояние. Документация: props, списки и key, условия.