Strona główna / Artykuły / React JSX wygląda jak HTML – jest kompilowany do JavaScript.

React JSX wygląda jak HTML – jest kompilowany do JavaScript.

JSX to markup w JavaScript: jeden korzeń, zamknięte tagi, atrybuty w formacie camelCase oraz nawiasy klamrowe dla wyrażeń — z klasycznymi zasadami, z którymi muszą się zmierzyć początkujący.

1208 słów

JSX wygląda jak HTML w pliku komponentu, ale jest kompilowany do JavaScript — i to właśnie wyjaśnia niemal każdą zasadę składni.

W poprzednich rozdziałach często określano znaczniki zwracane przez komponent — na przykład <h1>Hello</h1> — jako nieformalne „znaczniki”. Ich prawdziwa nazwa to JSX. Cel jest prosty: traktować JSX jako JavaScript, który przypadkowo przypomina HTML. Gdy to stanie się jasne, większość widocznych zasad składni przestaje wydawać się arbitralna.

Dlaczego JSX — znaczniki i logika razem

W klasycznej pracy nad interfejsem użytkownika struktura znajdowała się w plikach HTML, a zachowanie — w plikach JavaScript. W praktyce trudno jest oddzielić wygląd przycisku od jego obsługi kliknięcia. React umieszcza oba elementy w jednej jednostce — komponencie — dlatego potrzebuje sposobu na zapisywanie znaczników wewnątrz JavaScript. Tą składnią jest JSX.

Wizualnie jest bliskie HTML. Ponieważ kompilator przekształca JSX w JavaScript, zasady są surowsze niż w HTML. Zacznijmy od trzech zasad, które najpierw dotyczą początkujących.

Trzy zasady JSX

Zasada 1 — jeden korzeń

Komponent może zwrócić tylko jeden drzewo JSX. Kilka elementów rodzeństwa musi znajdować się pod jednym rodzicem.

// 🔴 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>
);

Jeśli dodatkowy <div> spowoduje zagraconość DOM, umieść elementy rodzeństwa wewnątrz Fragmentu (<>...</>).

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

Dlaczego jeden korzeń? JSX staje się wartością JavaScript. Funkcja nie może zwrócić dwóch wartości jednocześnie bez ich spakowania; ta sama zasada obowiązuje w przypadku JSX. To, że „to jest JavaScript, a nie HTML”, sprawia, iż zasada ma sens.

Zasada 2 — zamknij każdy tag

HTML pozwala na użycie niektórych tagów, takich jak <img> lub <br>, bez tagu zamykającego. W JSX każdy tag musi być zamknięty. Tagi bez dzieci używają formy samozamykającej się />.

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

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

Zasada 3 — atrybuty w formacie camelCase

Atrybuty JSX stają się kluczami w obiekcie JavaScript, więc ich nazwy muszą odpowiadać konwencjom języka JavaScript (camelCase), a nie surowym nazwom z HTML. Często występują kolizje z wyrazami rezerwowanymi:

  • class → className (class jest wyrazem rezerwowanym w JavaScript)
  • for → htmlFor (for również jest wyrazem rezerwowanym)
// 🔴 straight from HTML
<div class="card">
  <label for="email">Email</label>
</div>

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

To samo mapowanie zamienia onclick na onClick, a tabindex na tabIndex. Nie ma potrzeby zapamiętywania całej listy – funkcja uzupełniania w edytorze oraz flaga TypeScript szybko poprawiają błędne nazwy.

Zakręcone nawiasy {} — JavaScript wewnątrz JSX

Tutaj JSX przestaje być statycznym szablonem. Ponieważ JSX to JavaScript, zakręcone nawiasy {} umożliwiają wstawienie wartości JavaScript bezpośrednio w tym miejscu. HTML może zawierać jedynie stały tekst, natomiast JSX potrafi wykonywać wyrażenia.

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

{name} jest zastępowane wartością pola name ('Jane'). Nawiasy mogą przyjmować każde wyrażenie – kod, który daje określoną wartość – a nie tylko same zmienne.

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

Nawiasy są również używane w wartościach atrybutów. W takim przypadku pomija się cudzysłowy wokół nawiasów.

function Avatar() {
  const user = { name: 'Jane Kim', imageUrl: '/me.png' };
  return <img src={user.imageUrl} alt={user.name} />;
}
  • src="..." — cudzysłowy oznaczają dosłowny ciąg znaków.
  • src={...} — nawiasy oznaczają wartość w JavaScript.

Dozwolone są tylko wyrażenia

Wewnątrz nawiasów można umieścić wyrażenie, które generuje wartość. Nie wolno umieszczać instrukcji, takich jak if, for czy 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>

Warunkowa interfejs użytkownika z wyrażeniami ternarnymi, && oraz podobnymi wzorcami należy omówić w osobnym rozdziale poświęconym warunkowemu renderowaniu. Na razie obowiązuje zasada: tylko kod generujący wartości może znajdować się wewnątrz nawiasów.

Dwukrotne nawiasy {{ }} — obiekt wewnątrz nawiasów

Wzorzec {{ }}, który często pojawia się w JSX, nie jest odrębną cechą języka. Jest to obiekt JavaScript { } umieszczony wewnątrz zewnętrznych nawiasów. Typowym przykładem są style wstępne.

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

W HTML używa się łańcucha takiego jak style="color: tomato". JSX przekazuje natomiast obiekt, więc nazwy właściwości mają formę camelCase (fontSize zamiast font-size), a wartości to zazwyczaj łańcuchy lub liczby. Jeśli podwójne nawiasy wydają się niejasne, najpierw rozdziel je na nazwaną zmienną.

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

Zewnętrzne nawiasy oznaczają „wstaw tutaj wartość JavaScript”; wewnętrzny obiekt stanowi tę wartość.

Jak pisać komentarze

Kommentarze w JSX również używają nawiasów: to komentarz blokowy w JavaScript zamknięty w {}.

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

Łączenie wszystkiego

Powyższe zasady mieszczą się w jednym komponencie karty produktu.

// 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;

To przykład wykorzystuje wszystkie trzy zasady strukturalne (jedna korzeń, zamknięte tagi, className) oraz każdy powszechny wzorzec nawiasów (interpolacja tekstu, atrybuty, operacje arytmetyczne, wyrażenia ternarne, obiekty stylu).

Podsumowanie

  • JSX to JavaScript, a nie HTML — dlatego składnia jest bardziej rygorystyczna niż w HTML.
  • Trzy zasady strukturalne: umieszczać elementy siostrzane w jednym korzeniu (wystarczy Fragment), zamykać każdy tag oraz używać atrybutów w formacie camelCase (class→className, for→htmlFor).
  • Nawiasy krzywe {} zawierają wyrażenie JavaScript, zarówno w tekście, jak i w atrybutach.
  • Tylko wyrażenia generujące wartości mogą znajdować się w nawiasach — nie zdania takie jak if czy for.
  • {{ }} to nie nowa składnia; jest to obiekt w nawiasach. Style inline to klasyczny przykład.
  • Naturalnym następnym krokiem jest dostarczanie danych do komponentu z zewnątrz — za pomocą props. Kodowanie obiektu product bezpośrednio w komponencie nadaje się do demonstracji; dzięki props temu sam ProductCard może wyświetlać wiele produktów, i właśnie w tym miejscu typowanie w TypeScript zaczyna odgrywać najważniejszą rolę.

    Odnośniki

    • Dokumentacja React na temat zapisu markup za pomocą JSX
    • Dokumentacja React na temat wstawiania wyrażeń

    Powiązane materiały

    • Częste błędy TypeScript w React i sposoby ich rozwiązania — Praktyczny przewodnik po pięciu najczęstszych kategoriach błędów TypeScript w aplikacjach React: props, wydarzenia, stan, dane asynchroniczne oraz dzieci — z jasnymi rozwiązaniami dla każdego z nich.
    • Skracanie React Prop-Drilling i God Components — Poznaj siedem konkretnych wzorców refaktoryzacji, które pomagają rozbić rozbudowane komponenty React poprzez izolację stanu, pobierania danych, uprawnień oraz logiki ładowania, zamiast jedynie dzielenia plików.