Компонент React это функция JavaScript, которая возвращает JSX: переиспользуемая часть UI, например кнопка, карточка или целая страница. Вы используете его как тег HTML, <Profile />, а React вызывает функцию, чтобы узнать, что поместить на экран. Приложения строятся вложением компонентов в другие компоненты.
App рендерит Profile дважды, а каждый Profile рендерит Avatar. Измените инициалы внутри Avatar, и обновятся оба профиля, потому что у них одно определение. Пока что все люди в этом списке одинаковые; следующая страница, пропсы, показывает, как передать каждому экземпляру свои данные.
Как написать компонент
У функционального компонента два требования:
- Его имя начинается с заглавной буквы:
Profile, а неprofile. - Он возвращает то, что React может отрендерить: JSX, строку, число,
null(ничего не рендерить) или массив из этого.
function Welcome() {
return <h1>Welcome back</h1>;
}
// Arrow functions work the same way
const Welcome = () => <h1>Welcome back</h1>;
Когда JSX занимает несколько строк, оберните его в круглые скобки после return. Без них return, за которым следует перенос строки, возвращает undefined, и всё после него игнорируется.
Почему имя должно начинаться с заглавной буквы
JSX смотрит на первую букву тега. Нижний регистр означает встроенный элемент HTML, поэтому <div> остаётся <div>. Заглавная буква означает «переменная в области видимости», поэтому <Profile /> вызывает вашу функцию Profile. Назовите компонент в нижнем регистре, и React вместо этого создаст неизвестный элемент HTML с таким именем:
Вторая строка показывает только подпись, а консоль показывает только Greeting ran. React поместил на страницу пустой тег <greeting> и ни разу не вызвал функцию в нижнем регистре. Сборка для разработки также предупреждает The tag <greeting> is unrecognized in this browser; превью работает как продакшен-сборка, поэтому вы видите только пропавший текст. Чтобы исправить, переименуйте функцию в Greetings, а тег в <Greetings />.
Композиция компонентов
Компоненты созданы для вложения. Страница это дерево: App наверху, затем части макета, затем всё более мелкие части вплоть до отдельных кнопок. Каждый компонент знает только о частях, которые рендерит напрямую, поэтому о них можно думать по одному.
У каждой LikeButton своё состояние, поэтому лайк одного поста не трогает остальные. Чтобы добавить кнопку «поделиться» к каждому посту, вы пишете её один раз и добавляете <ShareButton /> внутрь Post.
Когда выделять компонент
Жёсткого правила нет, но несколько признаков говорят, что часть заслуживает собственного компонента: одна и та же разметка встречается в двух местах, у части JSX своё состояние (как у кнопки лайка выше) или функция выросла настолько, что до её return приходится прокручивать. Разделение по этим линиям держит каждый компонент достаточно маленьким, чтобы прочитать его на одном экране. Слишком раннее разделение обходится дёшево: компонент это всего лишь функция, и слить два обратно легко.
Экспорт и импорт компонентов
Редакторы здесь содержат один файл, но в настоящем проекте компоненты лежат в своих файлах. У файла может быть один экспорт по умолчанию и сколько угодно именованных экспортов:
// Avatar.jsx
export default function Avatar({ initials }) {
return <div className="avatar">{initials}</div>;
}
// Badge.jsx
export function Badge({ label }) {
return <span className="badge">{label}</span>;
}
export function NewBadge() {
return <Badge label="new" />;
}
// Profile.jsx
import Avatar from './Avatar.jsx';
import { Badge, NewBadge } from './Badge.jsx';
export default function Profile() {
return (
<div>
<Avatar initials="AL" />
<Badge label="admin" />
<NewBadge />
</div>
);
}
Экспорт по умолчанию можно импортировать под любым именем; именованный экспорт импортируется в фигурных скобках под своим точным именем. Команды обычно выбирают один стиль и придерживаются его. Имена файлов обычно совпадают с компонентом: Avatar.jsx экспортирует Avatar.
Сохраняйте компоненты чистыми
React ожидает, что компонент во время рендера ведёт себя как чистая функция: одни и те же пропсы и состояние дают один и тот же JSX, а рендер не меняет ничего, что существовало до его запуска. React может рендерить компонент много раз, в моменты, которые вы не контролируете, поэтому компонент, который во время рендера меняет внешние переменные, каждый раз выдаёт разный результат.
Нечистые чашки начинаются с 1, 2, 3. Нажмите кнопку: с гостями ничего не изменилось, но нечистый список теперь показывает 4, 5, 6, потому что каждый рендер прибавлял к общей переменной guest. Чистые чашки получают номер из пропсов и остаются правильными. В разработке Strict Mode рендерит каждый компонент дважды, чтобы выявить именно такую ошибку; превью работает как продакшен-сборка, поэтому здесь сдвиг виден только при повторном рендере.
Менять что-то можно, только не во время рендера. Обновляйте состояние в обработчиках событий, а с внешним миром (таймерами, подписками, заголовком документа) общайтесь в эффектах.
Компоненты и элементы
Компонент это функция, Profile. Элемент это то, что создаёт JSX, когда вы пишете <Profile />: небольшой объект, который говорит «отрендери Profile с этими пропсами». React создаёт элементы, вызывает компоненты, которые в них названы, и превращает результат в DOM. Вы никогда не вызываете компонент сами как Profile(); вы пишете <Profile /> и даёте React вызвать его, чтобы он мог отслеживать его состояние и место в дереве.
Это место важно. В этом примере компонент объявлен внутри другого компонента, и это частая ошибка:
Напишите что-нибудь, затем нажмите кнопку: ваш текст исчезнет. Каждый рендер App создаёт совершенно новую функцию NameField, поэтому React видит на этом месте другой тип компонента и выбрасывает старый вместе с его состоянием. Перенесите NameField выше App, на верхний уровень файла, и текст переживёт каждый клик. Страница о рендеринге объясняет, как React решает, что сохранить.
Функциональные и классовые компоненты
До появления хуков в React 16.8 компоненты, которым нужно было состояние, писали как классы:
import { Component } from 'react';
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
Классовые компоненты всё ещё работают в React 19, и вы встретите их в старых проектах и в границах ошибок, которым по-прежнему нужен класс. Новый код использует функциональные компоненты с хуками, например useState и useEffect, которые делают ту же работу с меньшим количеством кода. Страница о классовых компонентах сопоставляет каждую возможность класса с её хуком.
Часто задаваемые вопросы
Что такое компонент в React?
Компонент это переиспользуемая часть UI, написанная как функция JavaScript, которая возвращает JSX. Вы используете его как тег HTML, <Profile />, а React вызывает функцию, чтобы узнать, что нарисовать.
Почему имена компонентов React должны начинаться с заглавной буквы?
JSX по первой букве решает, что такое тег. Тег в нижнем регистре, например <profile />, считается элементом HTML с именем profile, и ваша функция никогда не вызывается. Тег с заглавной буквы, например <Profile />, ссылается на ваш компонент.
Чем функциональные компоненты отличаются от классовых?
Оба описывают UI. Функциональные компоненты это обычные функции, они используют хуки для состояния и эффектов; классовые компоненты наследуют React.Component и используют методы вроде render и componentDidMount. В новом коде используют функциональные компоненты.
Что такое чистый компонент в React?
Чистый компонент возвращает один и тот же JSX для одних и тех же пропсов и состояния и ничего не меняет вне себя во время рендера. React полагается на это, чтобы рендерить компоненты так часто, как ему нужно, без сюрпризов.
Можно ли объявить компонент внутри другого компонента?
Лучше не надо. Компонент, объявленный внутри другого, становится новой функцией при каждом рендере, поэтому React каждый раз считает его другим компонентом и сбрасывает его состояние. Объявляйте компоненты на верхнем уровне файла.