Kurs JavaScript i React · Moduł 1: Podstawy React

Pierwszy komponent

5 min czytania
W tej lekcji10

W sercu React znajdują się komponenty - samodzielne, wielokrotnego użytku bloki kodu, które enkapsulują HTML, CSS i JavaScript. Komponenty są jak klocki LEGO, z których budujesz swój interfejs użytkownika. W tej lekcji stworzymy nasz pierwszy komponent React i zrozumiemy jego podstawową strukturę.

Czym jest komponent React?

Komponent React to funkcja JavaScript (lub klasa), która zwraca element React (JSX). Komponenty pozwalają podzielić interfejs użytkownika na niezależne, wielokrotnego użytku części i myśleć o każdej części osobno.

Tworzenie pierwszego komponentu funkcyjnego

Zacznijmy od stworzenia prostego komponentu funkcyjnego. Komponent funkcyjny to zwykła funkcja JavaScript, która zwraca JSX:

1// Plik: WelcomeMessage.jsx
2import React from 'react';
3
4function WelcomeMessage() {
5  return (
6    <div className="welcome-container">
7      <h1>Witaj w świecie React!</h1>
8      <p>To twój pierwszy komponent.</p>
9    </div>
10  );
11}
12
13export default WelcomeMessage;

Kluczowe elementy tego komponentu:

  1. Import React - import React from 'react'; (od Reacta 17 nie jest to konieczne: nowe przekształcenie JSX, którego używa Vite, samo dodaje potrzebny kod, dlatego w App.jsx z szablonu Vite tego importu nie ma; zobaczysz go jednak w starszym kodzie i w tej lekcji)
  2. Deklaracja funkcji - function WelcomeMessage() {...}
  3. Return z JSX - Funkcja zwraca JSX, który definiuje strukturę komponentu
  4. Export - export default WelcomeMessage; pozwala importować komponent w innych plikach

JSX - co to właściwie jest?

JSX (JavaScript XML) to rozszerzenie składni JavaScript, które pozwala pisać kod przypominający HTML bezpośrednio w JavaScript. Bez JSX, tworzenie elementów React byłoby znacznie bardziej skomplikowane:

1// Z JSX
2function WelcomeMessage() {
3  return (
4    <div className="welcome-container">
5      <h1>Witaj w świecie React!</h1>
6      <p>To twój pierwszy komponent.</p>
7    </div>
8  );
9}
10
11// Bez JSX (tak naprawdę React przetwarza JSX do tej postaci)
12function WelcomeMessage() {
13  return React.createElement(
14    'div',
15    { className: 'welcome-container' },
16    React.createElement('h1', null, 'Witaj w świecie React!'),
17    React.createElement('p', null, 'To twój pierwszy komponent.')
18  );
19}

Jak widać, JSX sprawia, że kod jest znacznie bardziej czytelny i przypomina HTML, z którym większość deweloperów jest zaznajomiona.

Zasady JSX

JSX wygląda jak HTML, ale ma kilka ważnych różnic:

  1. className zamiast class - Ponieważ "class" jest słowem kluczowym w JavaScript, w JSX używamy className do definiowania klas CSS
  2. Atrybuty używają camelCase - Atrybuty HTML jak onclick są zapisywane jako onClick w JSX
  3. Samozamykające się tagi - Tagi jak <img> muszą być zamknięte: <img />
  4. Wyrażenia JavaScript w JSX - Możesz używać wyrażeń JavaScript w nawiasach klamrowych: {expression}

Używanie właściwości (props)

Komponenty mogą przyjmować dane za pomocą właściwości (props). Props to sposób na przekazywanie danych z komponentu rodzica do komponentu dziecka:

1// Plik: WelcomeMessage.jsx
2function WelcomeMessage(props) {
3  return (
4    <div className="welcome-container">
5      <h1>Witaj, {props.name}!</h1>
6      <p>{props.message}</p>
7    </div>
8  );
9}
10
11export default WelcomeMessage;
12
13// Użycie komponentu
14<WelcomeMessage name="Kosmonauto" message="Gotowy na podróż przez galaktykę React?" />

Możemy też używać destrukturyzacji props, co czyni kod bardziej czytelnym:

1function WelcomeMessage({ name, message }) {
2  return (
3    <div className="welcome-container">
4      <h1>Witaj, {name}!</h1>
5      <p>{message}</p>
6    </div>
7  );
8}

Renderowanie warunkowe

Jedną z mocnych stron komponentów React jest możliwość renderowania różnych elementów w zależności od pewnych warunków:

1function WelcomeMessage({ name, isLoggedIn }) {
2  return (
3    <div className="welcome-container">
4      {isLoggedIn ? (
5        <h1>Witaj ponownie, {name}!</h1>
6      ) : (
7        <h1>Witaj, gościu! Zaloguj się, aby kontynuować.</h1>
8      )}
9    </div>
10  );
11}

Renderowanie list

Komponenty React świetnie nadają się do renderowania list danych:

1function AstronautList({ astronauts }) {
2  return (
3    <div className="astronaut-list">
4      <h2>Załoga misji kosmicznej:</h2>
5      <ul>
6        {astronauts.map(astronaut => (
7          <li key={astronaut.id}>
8            {astronaut.name} - {astronaut.role}
9          </li>
10        ))}
11      </ul>
12    </div>
13  );
14}
15
16// Użycie
17const crewMembers = [
18  { id: 1, name: "Jan Kowalski", role: "Kapitan" },
19  { id: 2, name: "Anna Nowak", role: "Naukowiec" },
20  { id: 3, name: "Tomasz Wiśniewski", role: "Inżynier" }
21];
22
23<AstronautList astronauts={crewMembers} />

Zwróć uwagę na atrybut key - jest on wymagany przy renderowaniu list, aby React mógł efektywnie aktualizować DOM przy zmianach w liście.

Stylizacja komponentów

Istnieje kilka sposobów na stylizację komponentów React:

1. Zewnętrzny arkusz CSS

1// WelcomeMessage.css
2.welcome-container {
3  padding: 20px;
4  border-radius: 8px;
5  background-color: #f5f5f5;
6  text-align: center;
7}
8
9// WelcomeMessage.jsx
10import React from 'react';
11import './WelcomeMessage.css';
12
13function WelcomeMessage({ name }) {
14  return (
15    <div className="welcome-container">
16      <h1>Witaj, {name}!</h1>
17    </div>
18  );
19}

2. Wbudowane style (Inline styles)

1function WelcomeMessage({ name }) {
2  const styles = {
3    container: {
4      padding: '20px',
5      borderRadius: '8px',
6      backgroundColor: '#f5f5f5',
7      textAlign: 'center'
8    },
9    heading: {
10      color: '#333',
11      fontSize: '24px'
12    }
13  };
14
15  return (
16    <div style={styles.container}>
17      <h1 style={styles.heading}>Witaj, {name}!</h1>
18    </div>
19  );
20}

3. CSS Modules

1// WelcomeMessage.module.css
2.container {
3  padding: 20px;
4  border-radius: 8px;
5  background-color: #f5f5f5;
6  text-align: center;
7}
8
9// WelcomeMessage.jsx
10import React from 'react';
11import styles from './WelcomeMessage.module.css';
12
13function WelcomeMessage({ name }) {
14  return (
15    <div className={styles.container}>
16      <h1>Witaj, {name}!</h1>
17    </div>
18  );
19}

Kompozycja komponentów

Jedną z największych zalet React jest możliwość komponowania większych interfejsów z mniejszych komponentów:

1// Button.jsx
2function Button({ onClick, children, color = 'blue' }) {
3  return (
4    <button
5      onClick={onClick}
6      style={{
7        backgroundColor: color,
8        color: 'white',
9        padding: '10px 15px',
10        border: 'none',
11        borderRadius: '4px',
12        cursor: 'pointer'
13      }}
14    >
15      {children}
16    </button>
17  );
18}

Podsumowanie

W tej lekcji nauczyliśmy się:

  • Czym są komponenty React i jak je tworzyć
  • Podstaw JSX i jego zasad
  • Jak używać props do przekazywania danych
  • Renderowania warunkowego i list
  • Różnych metod stylizacji komponentów
  • Kompozycji komponentów do budowy większych interfejsów

Komponenty są fundamentalnym elementem React, a zrozumienie ich działania jest kluczowe dla efektywnego rozwoju aplikacji React. W kolejnych modułach zagłębimy się bardziej w zaawansowane koncepcje, takie jak stan (state), cykl życia komponentów i hooki.

Kod do tej lekcji: App.jsx
1import React, { useState } from 'react';
2
3// Przykład komponentu funkcyjnego
4function SpaceshipCard({ name, type, speed, crew, status }) {
5  const statusColors = {
6    active: '#4caf50',
7    maintenance: '#ff9800',
8    docked: '#2196f3'
9  };
10
11  return (
12    <div style={{
13      backgroundColor: '#1a1a2e',
14      border: '2px solid #16213e',
15      borderRadius: '12px',
16      padding: '20px',
17      color: 'white',
18      transition: 'transform 0.2s',
19    }}>
20      <div style={{
21        display: 'flex',
22        justifyContent: 'space-between',
23        alignItems: 'center',
24        marginBottom: '15px'
25      }}>
26        <h3 style={{ margin: 0, color: '#00d4ff' }}>{name}</h3>
27        <span style={{
28          padding: '4px 12px',
29          backgroundColor: statusColors[status],
30          borderRadius: '20px',
31          fontSize: '12px',
32          fontWeight: 'bold'
33        }}>
34          {status.toUpperCase()}
35        </span>
36      </div>
37      <div style={{ display: 'grid', gap: '10px' }}>
38        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
39          <span style={{ color: '#888' }}>Typ:</span>
40          <span>{type}</span>
41        </div>
42        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
43          <span style={{ color: '#888' }}>Prędkość:</span>
44          <span>{speed} km/s</span>
45        </div>
46        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
47          <span style={{ color: '#888' }}>Załoga:</span>
48          <span>{crew} osób</span>
49        </div>
50      </div>
51    </div>
52  );
53}
54
55// Komponent z props i children
56function SpaceSection({ title, children }) {
57  return (
58    <section style={{
59      backgroundColor: '#0f0f23',
60      borderRadius: '16px',
61      padding: '25px',
62      marginBottom: '20px'
63    }}>
64      <h2 style={{
65        color: '#00d4ff',
66        borderBottom: '2px solid #16213e',
67        paddingBottom: '10px',
68        marginTop: 0
69      }}>
70        {title}
71      </h2>
72      {children}
73    </section>
74  );
75}
76
77// Główny komponent aplikacji
78export default function App() {
79  const [selectedShip, setSelectedShip] = useState(null);
80
81  const spaceships = [
82    { id: 1, name: 'Aurora', type: 'Statek badawczy', speed: 50000, crew: 12, status: 'active' },
83    { id: 2, name: 'Nebula', type: 'Statek transportowy', speed: 35000, crew: 8, status: 'docked' },
84    { id: 3, name: 'Phoenix', type: 'Statek bojowy', speed: 75000, crew: 25, status: 'maintenance' },
85    { id: 4, name: 'Odyssey', type: 'Statek kolonizacyjny', speed: 20000, crew: 500, status: 'active' },
86  ];
87
88  return (
89    <div style={{
90      fontFamily: 'Arial, sans-serif',
91      backgroundColor: '#0a0a1a',
92      minHeight: '100vh',
93      padding: '20px',
94      color: 'white'
95    }}>
96      <header style={{
97        textAlign: 'center',
98        marginBottom: '30px',
99        padding: '30px',
100        background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
101        borderRadius: '16px'
102      }}>
103        <h1 style={{ margin: 0, fontSize: '2.5rem' }}>Flota Kosmiczna</h1>
104        <p style={{ margin: '10px 0 0 0', opacity: 0.9 }}>
105          Zarządzaj statkami kosmicznymi za pomocą komponentów React
106        </p>
107      </header>
108
109      <SpaceSection title="Statki w systemie">
110        <div style={{
111          display: 'grid',
112          gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
113          gap: '20px'
114        }}>
115          {spaceships.map(ship => (
116            <div key={ship.id} onClick={() => setSelectedShip(ship)}>
117              <SpaceshipCard {...ship} />
118            </div>
119          ))}
120        </div>
121      </SpaceSection>
122
123      {selectedShip && (
124        <SpaceSection title="Szczegóły wybranego statku">
125          <div style={{
126            backgroundColor: '#1a1a2e',
127            padding: '20px',
128            borderRadius: '12px'
129          }}>
130            <h3 style={{ color: '#00d4ff', marginTop: 0 }}>{selectedShip.name}</h3>
131            <p>Ten statek typu "{selectedShip.type}" może pomieścić {selectedShip.crew} członków załogi.</p>
132            <p>Maksymalna prędkość: {selectedShip.speed.toLocaleString()} km/s</p>
133            <button
134              onClick={() => setSelectedShip(null)}
135              style={{
136                padding: '10px 20px',
137                backgroundColor: '#f44336',
138                color: 'white',
139                border: 'none',
140                borderRadius: '8px',
141                cursor: 'pointer'
142              }}
143            >
144              Zamknij
145            </button>
146          </div>
147        </SpaceSection>
148      )}
149
150      <div style={{
151        backgroundColor: '#1a1a2e',
152        padding: '20px',
153        borderRadius: '12px',
154        marginTop: '20px'
155      }}>
156        <h3 style={{ color: '#4caf50', marginTop: 0 }}>Kluczowe koncepcje komponentów:</h3>
157        <ul style={{ lineHeight: '1.8', color: '#ccc' }}>
158          <li><strong>Props</strong> - dane przekazywane do komponentu (name, type, speed...)</li>
159          <li><strong>Children</strong> - zawartość między tagami komponentu</li>
160          <li><strong>Kompozycja</strong> - komponenty mogą zawierać inne komponenty</li>
161          <li><strong>Reużywalność</strong> - SpaceshipCard używany wielokrotnie z różnymi danymi</li>
162        </ul>
163      </div>
164    </div>
165  );
166}

Widzisz błąd w tej lekcji?

Sprawdź się

Odpowiedz na pytania z tej lekcji. Wybierz odpowiedź, a od razu zobaczysz, czy jest poprawna.

  1. 1. Od jakiej litery musi zaczynać się nazwa komponentu, żeby JSX potraktował <Nazwa /> jako komponent, a nie znacznik HTML?

Zadania praktyczne w grze

  • Układanie w poziomie

    Ułóż poprawną składnię eksportu domyślnego komponentu React:

  • Edytor kodu

    Stwórz komponent StationModule: funkcję, która przyjmuje props i zwraca <div> z nazwą modułu (props.name) i statusem (props.status). Przykład: 'Moduł: Silniki | Status: Online'

  • Klikanie w kolejności

    Ułóż składnię komponentu funkcyjnego:

  • Edytor kodu

    Stwórz komponent SpaceCapsule przyjmujący { missionName, crew, destination }. Wyświetl: 'Misja: [missionName]', 'Załoga: [crew]', 'Cel: [destination]'. Użyj destrukturyzacji props.

  • Układanie w pionie

    Ułóż proces tworzenia komponentu React:

  • Edytor kodu

    Stwórz komponent Navigation w osobnym pliku (np. Navigation.jsx) i wyeksportuj go, a następnie zaimportuj go w App.jsx i wyrenderuj w komponencie głównym Spaceship.

Przydatne artykuły