Lekcja 3: JSX - Składnia i Podstawy

JSX (JavaScript XML) to rozszerzenie składni JavaScript, które pozwala na pisanie kodu przypominającego HTML bezpośrednio w plikach JavaScript. Jest to kluczowy element Reacta, który znacząco ułatwia tworzenie i wizualizację komponentów UI.

Czym jest JSX?

JSX to składnia, która wygląda jak HTML, ale w rzeczywistości jest "cukrem syntaktycznym" dla funkcji React.createElement(). Podczas kompilacji, kod JSX jest przekształcany w standardowy JavaScript, który przeglądarki mogą zrozumieć.

Porównajmy dwa sposoby tworzenia elementów React:

// Bez JSX (czysty JavaScript)
const element = React.createElement(
  \'div\',
  { className: \'container\' },
  React.createElement(\'h1\', null, \'Witaj, świecie!\'),
  React.createElement(\'p\', null, \'To jest przykład bez JSX.\')
);

// Z JSX
const element = (
  <div className="container">
    <h1>Witaj, świecie!</h1>
    <p>To jest przykład z JSX.</p>
  </div>
);

Jak widać, JSX jest znacznie bardziej czytelny i intuicyjny, szczególnie dla osób znających HTML.

Podstawowe zasady JSX

1. Elementy JSX muszą być zamknięte

W HTML niektóre tagi nie wymagają zamknięcia (np. <img>, <input>). W JSX wszystkie elementy muszą być zamknięte, albo za pomocą tagu zamykającego, albo jako tag samozamykający z ukośnikiem na końcu.

// Poprawne
<div>Zawartość</div>
<img src="logo.png" alt="Logo" />
<input type="text" />

// Niepoprawne - brak zamknięcia
<img src="logo.png" alt="Logo">
<input type="text">

2. Atrybuty HTML vs. Właściwości JSX

Większość atrybutów HTML ma takie same nazwy w JSX, ale są wyjątki:

// Poprawne
<div className="container">
  <label htmlFor="username">Nazwa użytkownika:</label>
  <input id="username" onClick={handleClick} tabIndex={1} />
</div>

// Niepoprawne - użycie atrybutów HTML zamiast właściwości JSX
<div class="container">
  <label for="username">Nazwa użytkownika:</label>
  <input id="username" onclick={handleClick} tabindex={1} />
</div>

3. Wyrażenia JavaScript w JSX

Możemy osadzać wyrażenia JavaScript w JSX, umieszczając je w nawiasach klamrowych {}. Wyrażenia te są ewaluowane i ich wynik jest renderowany.

const name = \'Jan\';
const age = 25;

const element = (
  <div>
    <h1>Witaj, {name}!</h1>
    <p>Masz {age} lat.</p>
    <p>Za rok będziesz mieć {age + 1} lat.</p>
    <p>{name.toUpperCase()} to twoje imię zapisane wielkimi literami.</p>
  </div>
);

4. Komentarze w JSX

Komentarze w JSX muszą być umieszczone wewnątrz nawiasów klamrowych i mają standardową składnię komentarzy JavaScript.

const element = (
  <div>
    {/* To jest komentarz w JSX */}
    <h1>Witaj, świecie!</h1>
  </div>
);

5. JSX może mieć tylko jeden element główny

Każde wyrażenie JSX musi mieć dokładnie jeden element główny (root). Jeśli chcesz zwrócić wiele elementów, musisz je opakować w kontener (np. <div>) lub użyć fragmentu React (<></> lub <React.Fragment></React.Fragment>).

// Niepoprawne - brak jednego elementu głównego
const element = (
  <h1>Tytuł</h1>
  <p>Paragraf</p>
);

// Poprawne - elementy opakowane w div
const element = (
  <div>
    <h1>Tytuł</h1>
    <p>Paragraf</p>
  </div>
);

// Poprawne - użycie fragmentu (nie dodaje dodatkowego div do DOM)
const element = (
  <>
    <h1>Tytuł</h1>
    <p>Paragraf</p>
  </>
);

// Alternatywna składnia fragmentu
const element = (
  <React.Fragment>
    <h1>Tytuł</h1>
    <p>Paragraf</p>
  </React.Fragment>
);

Warunkowe renderowanie w JSX

JSX nie ma wbudowanych instrukcji warunkowych jak if czy for, ale możemy używać wyrażeń JavaScript do warunkowego renderowania.

Operator trójargumentowy

const element = (
  <div>
    {isLoggedIn ? (
      <h1>Witaj, użytkowniku!</h1>
    ) : (
      <h1>Proszę się zalogować.</h1>
    )}
  </div>
);

Operator logiczny AND (&&)

const element = (
  <div>
    {isLoggedIn && <h1>Witaj, użytkowniku!</h1>}
  </div>
);

Zmienne pomocnicze

let greeting;
if (isLoggedIn) {
  greeting = <h1>Witaj, użytkowniku!</h1>;
} else {
  greeting = <h1>Proszę się zalogować.</h1>;
}

const element = (
  <div>
    {greeting}
  </div>
);

Renderowanie list w JSX

Możemy używać metody map() do renderowania list elementów.

const numbers = [1, 2, 3, 4, 5];

const listItems = numbers.map((number) => 
  <li key={number.toString()}>{number}</li>
);

const element = (
  <ul>
    {listItems}
  </ul>
);

// Alternatywnie, bezpośrednio w JSX
const element = (
  <ul>
    {numbers.map((number) => 
      <li key={number.toString()}>{number}</li>
    )}
  </ul>
);

Zauważ atrybut key - jest on wymagany przez React podczas renderowania list, aby efektywnie śledzić zmiany elementów. Klucze powinny być unikalne wśród rodzeństwa (siblings).


Ćwiczenie praktyczne

Pokaż rozwiązanie

Rozwiązanie jest przedstawione w powyższym kodzie. Po uruchomieniu aplikacji powinieneś zobaczyć kartę produktu z obrazem, nazwą, ceną, opisem, informacją o dostępności i przyciskiem.

Cel: Stworzyć komponent, który renderuje kartę produktu z wykorzystaniem JSX.

Kroki:

  1. Otwórz projekt React (stworzony np. za pomocą Vite).
  2. W pliku App.jsx (lub nowym komponencie) zdefiniuj dane produktu:
// App.jsx
import React from \'react\';
import \'./App.css\';

function App() {
  const product = {
    name: "Smartfon XYZ",
    price: 1299.99,
    description: "Najnowszy model z ekranem 6.5 cala i potężnym procesorem.",
    inStock: true,
    imageUrl: "https://via.placeholder.com/150"
  };

  return (
    <div className="product-card">
      <img src={product.imageUrl} alt={product.name} />
      <h2>{product.name}</h2>
      <p className="price">{product.price} zł</p>
      <p>{product.description}</p>
      {product.inStock ? (
        <p className="in-stock">Dostępny</p>
      ) : (
        <p className="out-of-stock">Niedostępny</p>
      )}
      <button>Dodaj do koszyka</button>
    </div>
  );
}

export default App;
  • Dodaj style CSS (w pliku App.css):
  • /* App.css */
    .product-card {
      border: 1px solid #ddd;
      border-radius: 8px;
      padding: 16px;
      max-width: 300px;
      margin: 0 auto;
      text-align: center;
    }
    
    .product-card img {
      max-width: 100%;
      border-radius: 4px;
    }
    
    .price {
      font-weight: bold;
      color: #e44d26;
    }
    
    .in-stock {
      color: green;
    }
    
    .out-of-stock {
      color: red;
    }
    
    button {
      background-color: #4caf50;
      color: white;
      border: none;
      padding: 8px 16px;
      border-radius: 4px;
      cursor: pointer;
    }
    
    button:hover {
      background-color: #45a049;
    }
    
  • Uruchom aplikację (npm run dev) i sprawdź, czy karta produktu jest poprawnie wyświetlana.

  • Zadanie do samodzielnego wykonania

    Rozbuduj kartę produktu z ćwiczenia praktycznego o następujące elementy:

    1. Dodaj tablicę z cechami produktu (np. features: ["Ekran 6.5 cala", "Pamięć 128GB", "Aparat 48MP"]).
    2. Wyświetl te cechy jako listę nieuporządkowaną (<ul>) z elementami <li>.
    3. Dodaj ocenę produktu (np. rating: 4.5) i wyświetl ją.
    4. Dodaj pole discount: true/false i jeśli produkt jest na promocji, wyświetl odpowiednią informację.
    5. Użyj fragmentu React (<></>) zamiast div jako głównego kontenera.

    FAQ - JSX - Składnia i Podstawy

    Czy JSX jest językiem programowania?

    JSX nie jest odrębnym językiem programowania, lecz rozszerzeniem składni JavaScript. Jest to "cukier syntaktyczny", który ułatwia pisanie elementów UI w React. Podczas kompilacji, JSX jest przekształcany w standardowe wywołania funkcji JavaScript (React.createElement).

    Czy muszę używać JSX w React?

    Nie, JSX nie jest wymagany w React. Można pisać aplikacje React używając czystego JavaScript i funkcji React.createElement(). Jednak JSX znacznie poprawia czytelność kodu i jest powszechnie stosowany w społeczności React, więc jego nauka jest zdecydowanie zalecana.

    Dlaczego w JSX używamy className zamiast class?

    W JSX używamy className zamiast class, ponieważ "class" jest zarezerwowanym słowem kluczowym w JavaScript. Ponieważ JSX jest bliżej JavaScript niż HTML, używa camelCase dla nazw właściwości, zgodnie z konwencją JavaScript, zamiast nazw atrybutów HTML.

    Jak działa renderowanie warunkowe w JSX?

    JSX nie ma wbudowanych instrukcji warunkowych, ale możemy używać wyrażeń JavaScript. Popularne metody to: operator trójargumentowy (condition ? true : false), operator logiczny AND (condition && element), zmienne pomocnicze z if/else przed renderowaniem, lub funkcje pomocnicze zwracające elementy JSX.

    Co to jest "key" w listach React i dlaczego jest ważny?

    Atrybut "key" to specjalny identyfikator, który pomaga React śledzić, które elementy listy zostały zmienione, dodane lub usunięte. Klucze muszą być unikalne wśród rodzeństwa. Bez kluczy, React może nieprawidłowo aktualizować DOM, co prowadzi do błędów i problemów z wydajnością.

    Czy mogę używać komentarzy HTML w JSX?

    Nie, komentarze HTML (<!-- komentarz -->) nie działają w JSX. Zamiast tego używamy standardowych komentarzy JavaScript, ale muszą być one umieszczone wewnątrz nawiasów klamrowych: {/* komentarz */}. Jest to zgodne z zasadą, że wszystkie wyrażenia JavaScript w JSX są umieszczane w nawiasach klamrowych.

    Co to są fragmenty React i kiedy ich używać?

    Fragmenty React (<></> lub <React.Fragment></React.Fragment>) pozwalają grupować listę elementów bez dodawania dodatkowego węzła do DOM. Są użyteczne, gdy potrzebujesz zwrócić wiele elementów z komponentu, ale nie chcesz dodawać niepotrzebnego div lub innego kontenera do struktury DOM.