React

Компоненты и props

Кнопка Like в ленте Facebook встречается на экране десятки раз: под постом, под комментарием, в уведомлении. Если бы каждую из них верстали отдельно, любая правка дизайна означала бы ручной обход сотен мест. Вместо этого существует один компонент LikeButton, а различия - текст, счётчик, состояние нажатия - передаются ему параметрами. Меняется компонент в одном файле, и обновляются все его экземпляры разом. Это и есть главный приём React: интерфейс собирается из переиспользуемых деталей, как из деталей конструктора.

  • Design-системы вроде Material UI и shadcn/ui - это библиотеки готовых компонентов, настраиваемых через props
  • Карточка товара в Shopify, ячейка ленты в Instagram, строка таблицы в админке - всё это один компонент, отрисованный с разными данными
  • Storybook позволяет разрабатывать и показывать компоненты изолированно, подавая им разные наборы props
  • Чем мельче и чище компоненты, тем проще их тестировать: на вход props, на выходе предсказуемый JSX

Предварительные знания

  • JSX: теги компилируются в объекты-элементы, в фигурных скобках живут выражения
  • JavaScript-функции, объекты и деструктуризация объекта в параметрах
  • Идея односторонего потока данных из вводного урока

Компонент - это функция, возвращающая JSX

Компонент в современном React - обычная JavaScript-функция. Она принимает один аргумент (объект props) и возвращает JSX. Никакого особого синтаксиса для объявления нет: это просто функция, чьё имя начинается с большой буквы. Имя с большой буквы - не стиль, а требование: в JSX тег с маленькой буквы трактуется как DOM-элемент (div, span), а тег с большой - как компонент. Из-за регистра React и решает, что рендерить.

Имя с маленькой буквы ломает рендер молча. <welcome /> React считает неизвестным HTML-тегом и просто не отрисует компонент, не выдав ошибки. Поэтому правило 'компонент с большой буквы' критично.

Функция-компонент должна оставаться чистой по входу: при одних и тех же props она возвращает один и тот же JSX и не порождает побочных эффектов во время рендера. Это даёт предсказуемость, на которой держится вся модель React.

Почему имя компонента обязано начинаться с большой буквы?

Props: входные данные только для чтения

Props - это аргументы компонента. В JSX они выглядят как атрибуты, но передать можно любое значение: строку, число, объект, массив, функцию, даже другой JSX. Внутри компонента props доступны только для чтения. Компонент не имеет права менять полученный объект - он лишь читает данные и описывает по ним интерфейс. Это и делает поток данных односторонним и предсказуемым.

Деструктуризация в параметрах делает сигнатуру самодокументируемой: сразу видно, какие данные компонент ожидает. Значения по умолчанию задаются прямо в деструктуризации и подставляются, когда prop не передан.

Мутация props - частая ошибка новичка. Строка props.amount = 0 внутри компонента нарушает однонаправленный поток данных и приводит к багам, которые трудно отследить. Менять нужно состояние родителя через колбэк, а не сам props.

Что произойдёт, если компонент изменит полученный prop напрямую?

Композиция и children

React предпочитает композицию наследованию. Сложный интерфейс собирается вложением компонентов друг в друга: один компонент использует другой в своём JSX. Чтобы компонент мог обернуть произвольное содержимое, существует специальный prop children. Всё, что записано между открывающим и закрывающим тегом компонента, попадает в props.children.

Card ничего не знает о том, что внутри: текст, кнопка, другой компонент - всё придёт через children. Этот приём делает компоненты-контейнеры (модальные окна, панели, лейауты) по-настоящему переиспользуемыми. Один Card обслуживает любое содержимое.

  • Через props — Данные передаются как именованные значения: title, amount, src. Подходит для конкретных параметров
  • Через children — Произвольная разметка вкладывается внутрь тега. Подходит для обёрток, чьё содержимое заранее неизвестно

Composition over inheritance - официальная рекомендация документации React. Классов и наследования в современном React почти нет: вместо них компоненты комбинируют друг друга через props и children.

Что попадает в props.children компонента?

Связь с другими темами

Компоненты и props - это словарь React. На нём строится почти всё дальше:

  • Списки и keys — Один компонент карточки рендерится в цикле по массиву данных - типичная композиция
  • useState — Props приходят снаружи, состояние рождается внутри - их различие важно понимать сразу
  • Подъём состояния — Данные вниз через props, события вверх через колбэки - прямое продолжение этого урока

Итог

  • Компонент - это функция, которая принимает объект props и возвращает JSX
  • Props доступны только для чтения: компонент никогда не меняет то, что ему передали, иначе ломается предсказуемость
  • Данные текут в одну сторону - сверху вниз, от родителя к ребёнку через props
  • Композиция: компоненты вкладываются друг в друга, а произвольное содержимое передаётся через специальный prop children
  • Деструктуризация в параметрах и значения по умолчанию делают сигнатуру компонента читаемой
  • Имена компонентов пишутся с большой буквы, иначе JSX примет их за обычный HTML-тег

Связанные уроки

  • rc-02-jsx — Компонент возвращает JSX, поэтому без понимания JSX про компоненты говорить рано
  • rc-06-usestate — Props - это входные данные снаружи, а useState добавляет собственное внутреннее состояние компонента
  • rc-09-lifting-state — Поток данных вниз через props и событий вверх через колбэки - основа подъёма состояния
Компоненты и props

0

1

Войти