Галоўная / Артыкулы / React JSX выглядае як HTML — ён компілюецца у JavaScript.

React JSX выглядае як HTML — ён компілюецца у JavaScript.

JSX — это маркап языка JavaScript: адзін коранавой элемент, закрытыя тэгі, атрыбуты у формате camelCase і круглыя скобкі для выразаў — з класычнымі правіламі, з якімая сталкаюцца пачатківцы.

1208 слоў

JSX выглядае як HTML у файле компанента, але ён кампілюецца у JavaScript — і гэты факт пояснюе практычна всі правілы синтаксису.

У паканяніх роздзелах частаюць адносіць маркап, які вяртае компанент — напрыклад <h1>Hello</h1> — да неформальнага тэрміна „маркап“. Насправды ж гэта JSX. Мета простая: спрацавляць з JSX як з JavaScript, який простаўляеся як HTML. Калі гэта стане зрозумелым, большасць видных правіл синтаксису перестае здавацца довільнымі.

Чаму JSX — маркап і логіка разам

У класычным фронт-енд развіцці структура знаходзілася ў файлах HTML, а поведзенне — у файлах JavaScript. У практыцы важка адделіць выгляд кнопкі і елемент, який обрабоўвае ёё нажатыя. React размешчае і тое, і другое ў адной ейкавай — компаненте — таму яму патрэбны спосабы напісаць маркап унутро JavaScript. Гэты синтаксіс — JSX.

З візуальной точкі зоры ён супакоўваецца з HTML. Адтолькі, кампайляр ператварае JSX у JavaScript, таму правіла ў яму строгейшыя, чым у HTML. Пачніце з трох простых правілаў, якія падходзяць для пачаткуючых.

Тры правілы JSX

Правіла 1 — адна карэнная елемента

Компонент можа вярнуць толькі адну дрэва JSX. Калькі сяброўскія элементы павінны знаходзіцца пад адним карэнным элементам.

// 🔴 two siblings side by side — error
return (
  <h1>Title</h1>
  <p>Content</p>
);

// ✅ wrapped in one
return (
  <div>
    <h1>Title</h1>
    <p>Content</p>
  </div>
);

Якщо дадатковы <div> будзе паспяліваць DOM, абгорніце сяброўскія элементы ў Fragment (<>...</>).

return (
  <>
    <h1>Title</h1>
    <p>Content</p>
  </>
);

Чаму адна карэнная елемента? JSX становіцься значэннем у JavaScript. Функцыя не можа вярнуць два значэння адразу без іх упаковкі; тая ж ідея застосоўваецца і да JSX. Самэ тое, што ён — JavaScript, а не HTML, робіць гэтае правіла зрозумелым.

Правіла 2 — завяршваць кожную тагу

HTML дазваляе наявнасць дзеяных тагоў, такіх як <img> або <br>, без замкнучага тага. У JSX кожны таг павінен быць замкнуты. Тагі, які не маюць дзецячых элементаў, выкарыстоваюць формат самазамыкання />.

// 🔴 an HTML habit — error
<img src="logo.png">
<input type="text">

// ✅ self-closing
<img src="logo.png" />
<input type="text" />

Правіла 3 — атрыбуты у формате camelCase

Атрыбуты JSX стаюць ключамі ў об’екте JavaScript, таму іх назвы павінны адпавядаць стандартам JavaScript (camelCase), а не простым назвам HTML. Часта выступаюць супершчэпленні з резерваванымі словамі:

  • class → className (class ў JavaScript ёсць резерваваным словам)
  • for → htmlFor (for таксама ёсць резерваваным словам)
// 🔴 straight from HTML
<div class="card">
  <label for="email">Email</label>
</div>

// ✅ the JSX way
<div className="card">
  <label htmlFor="email">Email</label>
</div>

Той жа прыемка ператварае onclick на onClick, а tabindex — на tabIndex. Не трэба запамятаваць весь спіс: адгукатар рэдагувальніка і флажок TypeScript быстра выяўляюць некоректныя назвы.

Закіркаваныя кранцы {} — JavaScript унутрь JSX

Сюды JSX перестае быць статычным шаблонам. Паколькі JSX — это JavaScript, закіркаваныя кранцы {} дозволяюць прадаўаць значэнне JavaScript на тым месцы. HTML можа хаваць толькі фіксаваны текст; JSX можа вырахоўваць выразы.

function Greeting() {
  const name = 'Jane';
  return <h1>Hello, {name}!</h1>; // inside the braces is JavaScript
}

{name} заменяецца на значэнне name ('Jane'). Кранцы могу прыймаць будзь-які выраз — код, який вырахоўвае значэнне — а не толькі простыя зменныя.

function Bill() {
  const price = 12000;
  const count = 3;
  return (
    <div>
      <p>Unit price: {price} won</p>
      <p>Quantity: {count}</p>
      <p>Total: {price * count} won</p>          {/* arithmetic works too */}
      <p>{new Date().getFullYear()} receipt</p>  {/* function calls work too */}
    </div>
  );
}

Кранцы таксама выкорыстоўваюцца у значэннях атрыбутаў. У такім случыку не трэба ставіць апошнія знакі ў кранцы.

function Avatar() {
  const user = { name: 'Jane Kim', imageUrl: '/me.png' };
  return <img src={user.imageUrl} alt={user.name} />;
}
  • src="..." — апостраблі означаюць буквальны строку.
  • src={...} — квадратныя скобкі означаюць значэнне JavaScript.

Дазволены толькі выразы

Усередине квадратных скобак можна размістіць выраз, які гэнеруе значэнне. Нельга размішчаць заявы, такія як if, for чы const.

// 🔴 an if statement isn't an expression, so this fails
<p>{if (count > 0) 'in stock'}</p>

// ✅ the ternary operator is an expression, so it works
<p>{count > 0 ? 'in stock' : 'out of stock'}</p>

Умовны інтерфейс з тернарнымі выразамі, && і падобнымі шаблонамі належыць у спецыяльны роздзел пра умовную відрасліванне. Наразе дзейнічная правіла: толькі код, які гэнеруе значэнне, можа быць у квадратных скобаках.

Двойныя квадратныя скобкі {{ }} — об’ект усередине скобак

Шаблон {{ }}, які часта выкарыстоўваюцца ў JSX, не являецца окремай фічыяю мовы. Цэў об’ект JavaScript { }, які знаходзится ўнутрь зяўніх складаных краноцоў. Тыповым прыкладам являюцца стылі ўнутрь элемента.

// outer { } = "I'm putting JavaScript here"
// inner { } = the object itself
<div style={{ color: 'tomato', fontSize: 20 }}>styled</div>

У HTML выкарыстоўваецца строка на кшталт style="color: tomato". У JSX перадаецца об’ект, таму назвы атрыбутаў пішуцца у формате camelCase (fontSize замест font-size) а ў значэннях зазвычай выкарыстоўваюцца строкі чы рэчы. Якщо подвойныя краноцы здаюцца незрозумелымі, спачатку перакладзіце іх у зменную з іменам.

const cardStyle = { color: 'tomato', fontSize: 20 };
<div style={cardStyle}>styled</div>   // exactly the same as above

Зяўні краноц означае „вставіць тут значэнне JavaScript“; внутрзяны об’ект — гэтае значэнне.

Як пісаць каментары

Каментары ўнутрь JSX таксама выкарыстоўваюць краноцы: каментар блока JavaScript, абгорнуты ў {}.

return (
  <div>
    {/* this is a comment inside JSX */}
    <h1>Title</h1>
  </div>
);

Аднаўленне всього разам

Вышэўказаныя правілы падходзяць для аднаго компонента карточкі продукту.

// src/ProductCard.tsx
function ProductCard() {
  const product = {
    name: 'Mechanical Keyboard',
    price: 89000,
    inStock: true,
    imageUrl: "https://picsum.photos/200/300",
  };

  return (
    <div className="card" style={{ padding: 16 }}>
      {/* image: self-closing + brace attributes */}
      <img src={product.imageUrl} alt={product.name} />

      <h2>{product.name}</h2>
      <p>Price: {product.price.toLocaleString()} won</p>

      {/* show stock with an expression (ternary) — more in the next chapter */}
      <p>{product.inStock ? 'In stock' : 'Out of stock'}</p>
    </div>
  );
}

export default ProductCard;

У тым прыкладзе выкарыстоўваныя ўсі тры структурныя правілы (адна коранавая елемента, закрытыя тэгі, className) і кожны распашчаты патэрн (вставка тексту, атрыбуты, арыметычныя вырачэння, трынарныя выразы, об’ект стылю).

Заключэнне

  • JSX — это JavaScript, а не HTML — самэўчынна синтаксіс ёй строгейшы за HTML.
  • Тры структурныя правілы: аб’еднаваць братоўскія елементы ў адну коранавую елемента (дапаможыць можа Fragment), закрываць кожны тэг, і вжываць атрыбуты у формате camelCase (class→className, for→htmlFor).
  • Распашчатыя канцэвкі {} маюць паводзіцца выразам JavaScript, будзь то ў тексте чы ў атрыбутах.
  • У канцэвкі могу ўжывацца толькі выразы, якія даюць значэнне — не запаведзі, такія як if чы for.
  • {{ }} — гэта не новая сынтаксіс; гэта об’ект у скобках. Інлайн-стылі ўтвараюць класычны прыклад.
  • Наступны логічны крок — падача даных у компонент ззовні — props. Хард-кодаванне об’екта product у самы компонент падходзіць толькі для дэманстрацыі; за дапамогою props той самы ProductCard можа атрыбутаваць многія продукты, і самэ гэта робіць типаванне ў TypeScript насупераключным.

    Справы

    • Документацыя React пра маркап з JSX
    • Документацыя React пра вбудовванне выразаў