Quick Start
Добро пожаловать в документацию React! Эта страница познакомит вас с большинством концепций React, которыми вы будете пользоваться каждый день.
Вы узнаете
- Как создавать и вкладывать компоненты
- Как добавлять разметку и стили
- Как отображать данные
- Как отрисовывать условия и списки
- Как реагировать на события и обновлять страницу
- Как обмениваться данными между компонентами
Создание и вложение компонентов
Приложения на React собираются из компонентов. Компонент — это часть пользовательского интерфейса, у которого есть собственная логика и внешность. Компонент может быть маленьким, как кнопка, или большим, как целая страница.
React-компоненты — это функции JavaScript, которые возвращают разметку:
function MyButton() {
return (
<button>Я кнопка</button>
);
}
Вы объявили компонент MyButton
, который можно вложить в другой компонент:
export default function MyApp() {
return (
<div>
<h1>Добро пожаловать в моё приложение</h1>
<MyButton />
</div>
);
}
Обратите внимание на то, что <MyButton />
начинается с заглавной буквы. Это отличительная черта компонентов React. Названия компонентов в React всегда должны начинаться с заглавной буквы, а теги HTML — с маленькой.
Посмотрите на результат:
function MyButton() { return ( <button> Я кнопка </button> ); } export default function MyApp() { return ( <div> <h1>Добро пожаловать в моё приложение</h1> <MyButton /> </div> ); }
Ключевые слова export default
указывают на основной компонент в файле. Для того, чтобы понять некоторые особенности синтаксиса JavaScript, можно пользоваться ресурсами MDN и learn.javascript.ru.
Написание разметки с JSX
Синтаксис разметки, который вы видели выше, называется JSX. Он не обязателен, но большинство проектов на React предпочитают его использовать из-за удобства. Все инструменты, которые мы рекомендуем для локальной разработки, поддерживают JSX.
JSX строже HTML. Вам нужно закрывать теги вроде <br />
. Ваш компонент также не может возвращать несколько JSX-тегов. Их нужно будет обернуть внутрь общего родителя, например, <div>...</div>
или пустую обёртку вида <>...</>
:
function AboutPage() {
return (
<>
<h1>Обо мне</h1>
<p>Привет.<br />Как дела?</p>
</>
);
}
Для того, чтобы перевести большое количество HTML-верстки в JSX, можно использовать онлайн-конвертер.
Добавление стилей
В React CSS-классы объявляются с помощью className
. Оно работает аналогично HTML-атрибуту class
:
<img className="avatar" />
В отдельном CSS-файле вы пишете для него CSS-правила:
/* В вашем CSS */
.avatar {
border-radius: 50%;
}
React не ограничивает вас в том, как добавлять CSS-файлы. В самом простом случае вы добавите тег <link>
в ваш HTML-файл. Если вы используете инструмент для сборки или фреймворк, обратитесь к его документации, чтобы понять, как добавить CSS-файл в ваш проект.
Отображение данных
Фигурные скобки внутри JSX-разметки позволяют использовать JavaScript, например, для того, чтобы отобразить свою переменную пользователю. Код ниже отобразит user.name
:
return (
<h1>
{user.name}
</h1>
);
Вы также можете использовать JavaScript в атрибутах JSX. В таком случае вам нужно поставить фигурные скобки вместо кавычек. Например, className="avatar"
передаёт строку "avatar"
как CSS-класс, а src={user.imageUrl}
считывает значение JavaScript-переменной user.imageUrl
и передаёт его в качестве атрибута src
:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
Вы также можете использовать в JSX более сложные выражения внутри фигурных скобок, например, сложение строк:
const user = { name: 'Hedy Lamarr', imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg', imageSize: 90, }; export default function Profile() { return ( <> <h1>{user.name}</h1> <img className="avatar" src={user.imageUrl} alt={'Фото ' + user.name} style={{ width: user.imageSize, height: user.imageSize }} /> </> ); }
В этом примере style={{}}
не является специальным синтаксисом, а представляет из себя обычный объект {}
внутри фигурных скобок JSX style={ }
. Вы можете использовать атрибут style
в случаях, когда ваши стили зависят от переменных JavaScript.
Условный рендеринг
В React не существует специального синтаксиса для описания условий, вместо этого можно использовать обычный код на JavaScript. Например, для условного рендеринга JSX-кода можно применять if
:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
Если вы предпочитаете писать более компактный код, используйте условный оператор ?
. В отличие от if
его можно использовать в JSX:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
Когда вам не нужна ветка else
, можно использовать более короткий логический оператор &&
:
<div>
{isLoggedIn && <AdminPanel />}
</div>
Все эти способы подходят и для задания условий в атрибутах. Если вам не знакомы такие синтаксические конструкции JavaScript, вы можете начать с использования if...else
.
Рендеринг списков
Для отрисовки списков компонентов вам будет нужно использовать такие возможности JavaScript, как цикл for
и функция массива map()
.
Например, представим, что у вас есть массив продуктов:
const products = [
{ title: 'Капуста', id: 1 },
{ title: 'Чеснок', id: 2 },
{ title: 'Яблоко', id: 3 },
];
Преобразуйте этот массив в массив элементов <li>
с помощью функции map()
внутри вашего компонента:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
Обратите внимание, что у <li>
есть атрибут key
. Для каждого элемента списка вам нужно задавать ключ в виде строки или числа, который позволит однозначно отделить этот элемент от остальных в списке. Обычно этот ключ берется из ваших данных, например, это может быть идентификатор из базы данных. React использует эти ключи при добавлении, удалении или изменении порядка элементов.
const products = [ { title: 'Капуста', isFruit: false, id: 1 }, { title: 'Чеснок', isFruit: false, id: 2 }, { title: 'Яблоко', isFruit: true, id: 3 }, ]; export default function ShoppingList() { const listItems = products.map(product => <li key={product.id} style={{ color: product.isFruit ? 'magenta' : 'darkgreen' }} > {product.title} </li> ); return ( <ul>{listItems}</ul> ); }
Обработка событий
Вы можете реагировать на события, объявляя внутри ваших компонентов функции обработчиков событий:
function MyButton() {
function handleClick() {
alert('Вы нажали на меня!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
Заметьте: у onClick={handleClick}
нет скобок в конце! Не вызывайте функцию обработчика событий: вам нужно просто её передать. React вызовет ваш обработчик событий, когда пользователь кликнет по кнопке.
Обновление экрана
Вам может понадобиться, чтобы компонент «помнил» какую-то информацию и отображал её. Например, вы хотите посчитать сколько раз была нажата кнопка. Для этого добавьте состояние в ваш компонент.
Сначала импортируйте useState
из React:
import { useState } from 'react';
Теперь можно объявить переменную состояния внутри вашего компонента:
function MyButton() {
const [count, setCount] = useState(0);
// ...
useState
вернет вам две вещи: текущее состояние (count
) и функцию (setCount
), которая обновляет его. Можно именовать их как вам угодно, но такого рода вещи принято называть [something, setSomething]
.
При первом показе кнопка count
будет иметь значение 0
, потому что вы передали 0
в useState()
. Для изменения состояния вызовите setCount()
и передайте туда новое значение. Клик на эту кнопку будет увеличивать счётчик:
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Кликнули {count} раз
</button>
);
}
React снова вызовет функцию вашего компонента. На этот раз count
будет равно 1
, затем 2
, и так далее.
Если вы рендерите один и тот же компонент несколько раз, то у каждого из них будет своё состояние. Попробуйте покликать на каждую кнопку по отдельности:
import { useState } from 'react'; export default function MyApp() { return ( <div> <h1>Независимо обновляющиеся счётчики</h1> <MyButton /> <MyButton /> </div> ); } function MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Кликнули {count} раз </button> ); }
Обратите внимание на то, как каждая кнопка “помнит” свое состояние count
и не влияет на другие кнопки.
Использование хуков
Функции, которые начинаются с use
, называются хуками. useState
— это встроенный хук в React. В справочнике API приводятся другие встроенные хуки. Также, вы можете писать свои собственные хуки, совмещая их с уже существующими.
У хуков больше ограничений, чем у других функций. Хуки могут вызываться только в начале ваших компонентов (или других хуков). Если вам нужен useState
в условии или цикле, выделите новый компонент и используйте его там.
Обмен данными между компонентами
В предыдущем примере у каждого MyButton
имеется своё собственное состояние count
, и при клике на каждую кнопку обновление count
происходило только у нажатой кнопки.
Однако, вы будете часто сталкиваться с ситуацией, когда вам будет нужно, чтобы компоненты имели общие данные и всегда обновлялись вместе.
Для того, чтобы оба компонента MyButton
отображали одно и то же значение count
, вам нужно перенести состояние из отдельных кнопок «выше», в ближайший компонент, содержащий эти компоненты.
В этом случае таким компонентом является MyApp
:
Теперь, когда вы нажимаете на любую из кнопок, count
в MyApp
будет менять своё значение, что в свою очередь повлечёт обновление счётчиков в обоих компонентах MyButton
. Вот как это можно выразить в коде.
Сначала переместите вверх состояние из MyButton
в MyApp
:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Независимо обновляющиеся счётчики</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... мы перемещаем код отсюда ...
}
Затем передайте состояние на уровень ниже из MyApp
каждому MyButton
вместе с общим обработчиком клика. Можно передавать информацию в MyButton
через фигурные скобки JSX таким же образом, как вы это делали со встроенными тегами наподобие <img>
:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Одновременно обновляющиеся счётчики</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
Информация, которую вы передаёте таким образом, называется пропсами. Теперь у компонента MyApp
есть состояние count
и обработчик событий handleClick
, которые он передаёт в качестве пропсов каждой кнопке-потомку.
Наконец, измените компонент MyButton
так, чтобы он считывал пропсы, переданные от своего родителя:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Кликнули {count} раз
</button>
);
}
При нажатии на кнопку срабатывает обработчик onClick
. Каждой кнопке в качестве значения пропа onClick
задана функция handleClick
из MyApp
, поэтому выполняется соответствующий код. Этот код вызывает функцию setCount(count + 1)
, увеличивая значение состояния count
. Новое значение count
передаётся каждой кнопке в качестве пропа, поэтому они все отображают новое значение. Это называется “подъёмом состояния вверх”. Поднимая состояние вверх, вы делаете его общим для всех компонентов.
import { useState } from 'react'; export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update together</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); } function MyButton({ count, onClick }) { return ( <button onClick={onClick}> Clicked {count} times </button> ); }
Следующие шаги
Теперь вы знаете основы того, как писать код для React!
Ознакомьтесь с введением, в рамках которого вы сможете применить полученные знания и собрать своё первое мини-приложение на React.