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 и событий вверх через колбэки - основа подъёма состояния