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.
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(classjest wyrazem rezerwowanym w JavaScript)for→htmlFor(forró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
ifczyfor.
{{ }} 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.