Швидкий старт

Ласкаво просимо до документації React! Ця сторінка ознайомить вас з 80% концепцій React, які ви будете використовувати щодня.

  • Як створювати та вкладати компоненти
  • Як додати розмітку та стилі
  • Як відображати дані
  • Як рендерити умови та списки
  • Як реагувати на події та оновлювати екран
  • Як обмінюватися даними між компонентами

Створення та вкладання компонентів

React-застосунки складаються з компонентів. Компонент - це частина інтерфейсу користувача (UI), яка має власну логіку та зовнішній вигляд. Компонент може бути як маленьким, як кнопка, так і великим, як ціла сторінка.

Компоненти React - це функції JavaScript, які повертають розмітку:

function MyButton() {
  return (
    <button>I'm a button</button>
  );
}

Тепер, коли ви оголосили MyButton, ви можете вкласти його в інший компонент:

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

Зверніть увагу, що <MyButton /> починається з великої літери. Так ви дізнаєтесь, що це React-компонент. Назви React-компонентів завжди мають починатися з великої літери, тоді як HTML-теги мають бути малими.

Погляньте на результат:

function MyButton() {
  return (
    <button>
      I'm a button
    </button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

Ключові слова експорту за замовчуванням визначають головний компонент у файлі. Якщо ви не знайомі з якоюсь частиною синтаксису JavaScript, MDN та javascript.info мають чудові посилання.

Запис розмітки за допомогою JSX

Синтаксис розмітки, який ви бачили вище, називається JSX. Він не є обов'язковим, але більшість React-проектів використовують JSX для зручності. Всі інструменти, які ми рекомендуємо для локальної розробки, підтримують JSX одразу після установки.

JSX суворіша за HTML. Ви повинні закривати теги на кшталт <br />. Ваш компонент також не може повертати декілька JSX-тегів. Ви повинні обгорнути їх у спільний батьківський тег, наприклад, <div>...</div> або порожній <>...</>:

function AboutPage() {
  return (
    <>
      <h1>About</h1>
      <p>Hello there.<br />How do you do?</p>
    </>
  );
}

Якщо ви маєте багато HTML для перенесення у JSX, ви можете скористатися онлайн-конвертером.

Додавання стилів

У React ви вказуєте клас CSS за допомогою className. Це працює так само, як і HTML-атрибут class:

<img className="avatar" />

Потім ви пишете правила CSS для нього в окремому файлі CSS:

/* In your CSS */
.avatar {
  border-radius: 50%;
}

React не визначає, як додавати CSS файли. У найпростішому випадку ви додаєте тег <link> до вашого HTML. Якщо ви використовуєте інструмент збірки або фреймворк, зверніться до його документації, щоб дізнатися, як додати CSS-файл до вашого проекту.

Відображення даних

JSX дозволяє вставляти розмітку у JavaScript. Фігурні дужки дозволяють вам "втекти назад" в 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={'Photo of ' + user.name}
        style={{
          width: user.imageSize,
          height: user.imageSize
        }}
      />
    </>
  );
}
.avatar {
  border-radius: 50%;
}

.large {
  border: 4px solid gold;
}

У наведеному вище прикладі style={{}} - це не спеціальний синтаксис, а звичайний об'єкт {} всередині фігурних дужок style={ } JSX. Ви можете використовувати атрибут style, якщо ваші стилі залежать від змінних JavaScript.

Умовний рендеринг

У React немає спеціального синтаксису для написання умов. Натомість, ви можете використовувати ті ж самі прийоми, що і при написанні звичайного JavaScript коду. Наприклад, ви можете використовувати інструкцію if, щоб умовно включити JSX:

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, як цикл та функцію масив map() для відображення списків компонентів.

Наприклад, припустимо, що у вас є масив товарів:

const products = [ { title: 'Cabbage', id: 1 }, { title: 'Garlic', id: 2 }, { title: 'Apple', id: 3 }, ];

Всередині вашого компонента використовуйте функцію map() для перетворення масиву продуктів у масив <li> елементів:

const listItems = products.map(product =>
  <li key={product.id}>
    {product.title}
  </li>
);

return (
  <ul>{listItems}</ul>
);

Зверніть увагу, що <li> має атрибут key. Для кожного елемента списку ви повинні передати рядок або число, яке однозначно ідентифікує цей елемент серед його братів і сестер. Зазвичай, ключ має походити з ваших даних, наприклад, ідентифікатора бази даних. React використовує ваші ключі, щоб знати, що сталося, якщо ви пізніше вставите, видалите або переупорядкуєте елементи.

const products = [
  { title: 'Cabbage', isFruit: false, id: 1 },
  { title: 'Garlic', isFruit: false, id: 2 },
  { title: 'Apple', 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('You clicked me!');
  }

  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}>
      Clicked {count} times
    </button>
  );
}

React знову викличе функцію вашого компонента. Цього разу count буде 1. Потім це буде 2. І так далі.

Якщо ви рендерите один і той самий компонент кілька разів, кожен з них отримає власний стан. Натискайте кожну кнопку окремо:

import { useState } from 'react';

export default function MyApp() {
  return (
    <div>
      <h1>Counters that update separately</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}
button {
  display: block;
  margin-bottom: 5px;
}

Зверніть увагу, що кожна кнопка "запам'ятовує" свій стан count і не впливає на інші кнопки.

Використання хуків

Функції, що починаються з use, називаються хуками. useState - це вбудований хук, що надається React. Ви можете знайти інші вбудовані хуки в API довіднику. Ви також можете писати власні хуки, комбінуючи існуючі.

Хуки більш обмежені, ніж інші функції. Ви можете викликати хуки лише у верхній частині ваших компонентів (або інших хуків). Якщо ви хочете використовувати useState в умові або циклі, витягніть новий компонент і помістіть його туди.

Обмін даними між компонентами

У попередньому прикладі кожна MyButton мала власний незалежний count, і при натисканні кожної кнопки змінювався лише count для натиснутої кнопки:

Diagram showing a tree of three components, one parent labeled MyApp and two children labeled MyButton. Both MyButton components contain a count with value zero.

Початково стан кожного MyButton у count є 0

.
The same diagram as the previous, with the count of the first child MyButton component highlighted indicating a click with the count value incremented to one. The second MyButton component still contains value zero.

Перший MyButton оновлює свій count до 1

Втім, часто вам потрібно, щоб компоненти ділилися даними і завжди оновлювалися разом.

Щоб обидва MyButton компоненти відображалися однаково count і оновлювалися разом, потрібно перемістити стан з окремих кнопок "нагору" до найближчого компонента, який містить їх усі.

У цьому прикладі це буде MyApp:

Diagram showing a tree of three components, one parent labeled MyApp and two children labeled MyButton. MyApp contains a count value of zero which is passed down to both of the MyButton components, which also show value zero.

Початковий стан MyApp у count є 0 і передається обом нащадкам

The same diagram as the previous, with the count of the parent MyApp component highlighted indicating a click with the value incremented to one. The flow to both of the children MyButton components is also highlighted, and the count value in each child is set to one indicating the value was passed down.

При натисканні, MyApp оновлює свій стан count до 1 і передає його обом нащадкам

Тепер, коли ви натиснете будь-яку з кнопок, значення count у MyApp зміниться, що призведе до зміни обох обчислень у MyButton. Ось як ви можете виразити це у коді.

По-перше, перемістіть стан вгору з MyButton у MyApp:

export default function MyApp() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <div>
      <h1>Counters that update separately</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

function MyButton() {
  // ... we're moving code from here ...
}

Далі, передайте стан вниз від MyApp до кожного MyButton, разом зі спільним обробником кліку. Ви можете передати інформацію до MyButton за допомогою фігурних дужок JSX, так само, як ви це робили раніше з вбудованими тегами на кшталт <img>:

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>
  );
}

Інформація, яку ви передаєте таким чином, називається проси. Тепер компонент MyApp містить стан count та обробник події handleClick, і передає їх обидва як пропси до кожної з кнопок.

Нарешті, змініть MyButton на пропси read, які ви передали з батьківського компонента:

function MyButton({ count, onClick }) {
  return (
    <button onClick={onClick}>
      Clicked {count} times
    </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>
  );
}
button {
  display: block;
  margin-bottom: 5px;
}

Наступні кроки

Тепер ви знаєте основи написання React-коду!

Ознайомтеся з Уроком, щоб застосувати їх на практиці та створити свій перший міні-застосунок з React.