Написання розмітки за допомогою JSX

JSX - синтаксичне розширення для JavaScript, яке дозволяє писати HTML-подібну розмітку у файлі JavaScript. Хоча є й інші способи написання компонентів, більшість React-розробників надають перевагу лаконічності JSX, і більшість кодових баз використовують саме його.

  • Чому React змішує розмітку з логікою рендерингу
  • Чим JSX відрізняється від HTML
  • Як виводити інформацію за допомогою JSX

JSX: додавання розмітки до JavaScript

Веб побудовано на HTML, CSS та JavaScript. Протягом багатьох років веб-розробники зберігали вміст у HTML, дизайн у CSS, а логіку у JavaScript - часто в окремих файлах! Вміст розмічався всередині HTML, а логіка сторінки жила окремо у JavaScript:

HTML markup with purple background and a div with two child tags: p and form.

HTML

Three JavaScript handlers with yellow background: onSubmit, onLogin, and onClick.

JavaScript

Але в міру того, як Інтернет ставав все більш інтерактивним, логіка все більше визначала зміст. JavaScript відповідав за HTML! Ось чому в React логіка рендерингу та розмітка живуть разом в одному місці - компонентах.

React component with HTML and JavaScript from previous examples mixed. Function name is Sidebar which calls the function isLoggedIn, highlighted in yellow. Nested inside the function highlighted in purple is the p tag from before, and a Form tag referencing the component shown in the next diagram.

Sidebar.js React-компонент

React component with HTML and JavaScript from previous examples mixed. Function name is Form containing two handlers onClick and onSubmit highlighted in yellow. Following the handlers is HTML highlighted in purple. The HTML contains a form element with a nested input element, each with an onClick prop.

Form.js React-компонент

Зберігання логіки рендерингу та розмітки кнопки разом гарантує, що вони залишатимуться синхронізованими під час кожного редагування. І навпаки, деталі, які не пов'язані між собою, наприклад, розмітка кнопки та розмітка бічної панелі, ізольовані одна від одної, що робить безпечнішою зміну будь-якої з них окремо.

Кожен React-компонент - це JavaScript-функція, яка може містити деяку розмітку, яку React відображає в браузері. Для представлення цієї розмітки React-компоненти використовують синтаксичне розширення JSX. JSX дуже схожий на HTML, але він трохи суворіший і може відображати динамічну інформацію. Найкращий спосіб зрозуміти це - перетворити деяку HTML-розмітку на JSX-розмітку.

JSX і React - це дві різні речі. Їх часто використовують разом, але ви можете використовувати їх незалежно один від одного. JSX - це синтаксичне розширення, а React - бібліотека JavaScript.

Перетворення HTML на JSX

Припустимо, що у вас є деякий (цілком коректний) HTML:

<h1>Hedy Lamarr's Todos</h1>
<img 
  src="https://i.imgur.com/yXOvdOSs.jpg" 
  alt="Hedy Lamarr" 
  class="photo"
>
<ul>
    <li>Invent new traffic lights
    <li>Rehearse a movie scene
    <li>Improve the spectrum technology
</ul>

І ви хочете додати його до свого компонента:

export default function TodoList() {
  return (
    // ???
  )
}

Якщо скопіювати і вставити його як є, він не працюватиме:

export default function TodoList() {
  return (
    // This doesn't quite work!
    <h1>Hedy Lamarr's Todos</h1>
    <img 
      src="https://i.imgur.com/yXOvdOSs.jpg" 
      alt="Hedy Lamarr" 
      class="photo"
    >
    <ul>
      <li>Invent new traffic lights
      <li>Rehearse a movie scene
      <li>Improve the spectrum technology
    </ul>
  );
}
img { height: 90px }

Це тому, що JSX суворіша і має дещо більше правил, ніж HTML! Якщо ви прочитаєте повідомлення про помилки вище, вони допоможуть вам виправити розмітку, або ви можете скористатися настановою нижче.

Здебільшого екранні повідомлення про помилки React допоможуть вам знайти проблему. Прочитайте їх, якщо ви застрягли!

.

Правила JSX

1. Повернути єдиний кореневий елемент

.

Щоб повернути декілька елементів з компонента, обгорніть їх одним батьківським тегом.

Наприклад, можна використати <div>:

<div>
  <h1>Hedy Lamarr's Todos</h1>
  <img 
    src="https://i.imgur.com/yXOvdOSs.jpg" 
    alt="Hedy Lamarr" 
    class="photo"
  >
  <ul>
    ...
  </ul>
</div>

Якщо ви не хочете додавати зайвий <div> до розмітки, ви можете написати <> та </> замість нього:

<>
  <h1>Hedy Lamarr's Todos</h1>
  <img 
    src="https://i.imgur.com/yXOvdOSs.jpg" 
    alt="Hedy Lamarr" 
    class="photo"
  >
  <ul>
    ...
  </ul>
</>

Цей порожній тег називається фрагментом. Фрагменти дозволяють групувати елементи, не залишаючи слідів у дереві HTML браузера.

Чому потрібно обгортати декілька JSX-тегів?

JSX виглядає як HTML, але за лаштунками він перетворюється на звичайні об'єкти JavaScript. Ви не можете повернути два об'єкти з функції, не обгорнувши їх у масив. Це пояснює, чому ви також не можете повернути два JSX-теги, не обгорнувши їх в інший тег або фрагмент.

2. закрити всі теги

JSX вимагає, щоб теги було явно закрито: самозакривні теги на кшталт <img> мають стати <img />, а обгорткові теги на кшталт <li>oranges повинні записуватися як <li>oranges</li>.

Так виглядають закриті зображення та елементи списку Хеди Ламарр:

<>
  <img 
    src="https://i.imgur.com/yXOvdOSs.jpg" 
    alt="Hedy Lamarr" 
    class="photo"
   />
  <ul>
    <li>Invent new traffic lights</li>
    <li>Rehearse a movie scene</li>
    <li>Improve the spectrum technology</li>
  </ul>
</>

3. camelCase всі більшість речей!

JSX перетворюється на JavaScript, а атрибути, написані на JSX, стають ключами об'єктів JavaScript. У ваших власних компонентах ви часто хотітимете прочитати ці атрибути у змінні. Але JavaScript має обмеження на імена змінних. Наприклад, їхні імена не можуть містити тире або бути зарезервованими словами на кшталт class.

Ось чому в React багато атрибутів HTML та SVG пишуться в camelCase. Наприклад, замість stroke-width ви використовуєте strokeWidth. Оскільки class є зарезервованим словом, у React замість нього ви пишете className, названий на честь відповідної властивості DOM:

<img 
  src="https://i.imgur.com/yXOvdOSs.jpg" 
  alt="Hedy Lamarr" 
  className="photo"
/>

Ви можете знайти всі ці атрибути у списку пропсів DOM-компонентів. Якщо ви помилилися з одним з них, не хвилюйтеся - React виведе повідомлення з можливим виправленням у консоль браузера.

З історичних причин атрибути aria-* та data-* записуються як у HTML з тире.

Порада: використовуйте конвертер JSX

Перетворення всіх цих атрибутів в існуючій розмітці може бути нудним! Ми рекомендуємо використовувати конвертер для перетворення існуючих HTML і SVG в JSX. Конвертери дуже корисні на практиці, але все ж варто розуміти, що відбувається, щоб ви могли комфортно писати JSX самостійно.

Ось ваш кінцевий результат:

export default function TodoList() {
  return (
    <>
      <h1>Hedy Lamarr's Todos</h1>
      <img 
        src="https://i.imgur.com/yXOvdOSs.jpg" 
        alt="Hedy Lamarr" 
        className="photo" 
      />
      <ul>
        <li>Invent new traffic lights</li>
        <li>Rehearse a movie scene</li>
        <li>Improve the spectrum technology</li>
      </ul>
    </>
  );
}
img { height: 90px }

Тепер ви знаєте, навіщо існує JSX і як його використовувати у компонентах:

  • Компоненти React групують логіку рендерингу разом з розміткою, оскільки вони пов'язані між собою.
  • JSX схожа на HTML, але з деякими відмінностями. Ви можете скористатися конвертером, якщо вам це потрібно.
  • Повідомлення про помилки часто вказують вам на правильний напрямок виправлення розмітки.

Перетворити деякий HTML на JSX

Цей HTML було вставлено у компонент, але він не є валідним JSX. Виправте це:

export default function Bio() {
  return (
    <div class="intro">
      <h1>Welcome to my website!</h1>
    </div>
    <p class="summary">
      You can find my thoughts here.
      <br><br>
      <b>And <i>pictures</b></i> of scientists!
    </p>
  );
}
.intro {
  background-image: linear-gradient(to left, violet, indigo, blue, green, yellow, orange, red);
  background-clip: text;
  color: transparent;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.summary {
  padding: 20px;
  border: 10px solid gold;
}

Зробити це вручну або за допомогою конвертера - вирішувати вам!

export default function Bio() {
  return (
    <div>
      <div className="intro">
        <h1>Welcome to my website!</h1>
      </div>
      <p className="summary">
        You can find my thoughts here.
        <br /><br />
        <b>And <i>pictures</i></b> of scientists!
      </p>
    </div>
  );
}
.intro {
  background-image: linear-gradient(to left, violet, indigo, blue, green, yellow, orange, red);
  background-clip: text;
  color: transparent;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

.summary {
  padding: 20px;
  border: 10px solid gold;
}