Szybki start
Witaj w dokumentacji Reacta! Ten rozdział przedstawi ci 80% zagadnień związanych z Reactem, których będziesz używać na co dzień.
W tej sekcji dowiesz się
- Jak tworzyć i zagnieżdżać komponenty
- Jak dodać kod znaczników i style
- Jak wyświetlać dane
- Jak renderować warunki i listy
- Jak reagować na zdarzenia i aktualizować interfejs
- Jak dzielić dane między komponentami
Tworzenie i zagnieżdżanie komponentów
Aplikacje reactowe składają się z komponentów. Komponent to kawałek UI (interfejsu użytkownika, ang. user interface), który ma swoją wyodrębnioną logikę i wygląd. Komponent może być mały, np. przycisk, lub duży, np. cała strona.
Komponenty reactowe to funkcje javascriptowe, które zwracają kod znaczników (ang. markup):
function MyButton() {
return (
<button>Jam jest przycisk</button>
);
}
Teraz gdy już mamy zadeklarowany komponent MyButton
, możemy go zagnieździć w innym komponencie:
export default function MyApp() {
return (
<div>
<h1>Witaj na mojej stronie</h1>
<MyButton />
</div>
);
}
Zauważ, że <MyButton />
zaczyna się od wielkiej litery. Po tym można poznać, że to komponent reactowy. Komponenty reactowe muszą zaczynać się od wielkie litery, natomiast znaczniki HTML muszą zaczynać się od małej litery.
Przyjrzyj się wynikowi poniższego kodu:
function MyButton() { return ( <button> Jam jest przycisk </button> ); } export default function MyApp() { return ( <div> <h1>Witaj na mojej stronie</h1> <MyButton /> </div> ); }
Słowa kluczowe export default
określają główny komponent pliku. Jeśli nie rozumiesz tego zagadnienia, zajrzyj do MDN oraz javascript.info po więcej szczegółów.
Pisanie kodu znaczników w składni JSX
Kod znaczników, który widzieliśmy w poprzedniej sekcji, nazywa się JSX. Nie jest on obowiązkowy, jednak większość projektów reactowych korzysta z niego dla wygody. Wszystkie polecane przez nas narzędzia do programowania w środowisku lokalnym domyślnie wspierają składnię JSX.
Składnia JSX jest bardziej restrykcyjna niż HTML. Zawsze trzeba w niej zamykać znaczniki, np. <br />
. Dodatkowo, twój komponent nie może zwracać kilku znaczników JSX jednocześnie. Jeśli chcesz zwrócić kilka elementów, musisz je opakować we wspólnego rodzica, np. <div>...</div>
lub pusty fragment <>...</>
:
function AboutPage() {
return (
<>
<h1>O mnie</h1>
<p>Cześć.<br />Jak się masz?</p>
</>
);
}
Jeśli masz już sporo kodu HTML i chcesz go przenieść do składni JSX, możesz skorzystać z konwertera online.
Dodawanie styli
W Reakcie klasy CSS-owe definiujemy za pomocą właściwości className
. Działa ona tak samo jak atrybut class
w HTML-u:
<img className="avatar" />
Deklaracje CSS piszemy w osobnym pliku:
/* W twoim pliku CSS */
.avatar {
border-radius: 50%;
}
React nie wymusza jednego sposobu dodawania plików CSS-owych. W najprostszym przypadku możesz dodać znacznik <link>
do kodu HTML strony. Jeśli korzystasz z jakiegoś narzędzia budującego lub frameworka, zajrzyj do ich dokumentacji, aby dowiedzieć się, jak poprawnie dodać pliki CSS do projektu.
Wyświetlanie danych
Składnia JSX pozwala umieszczać kod znaczników w kodzie javascriptowym. Za pomocą nawiasów klamrowych możesz “przeskoczyć” do JavaScriptu, aby umieścić jakąś zmienną i wyświetlić ją użytkownikowi. Na przykład, poniższy kod wyświetli wartość user.name
:
return (
<h1>
{user.name}
</h1>
);
“Przeskoczyć do JavaScriptu” możesz także w atrybutach komponentów, jednak musisz w tym celu użyć nawiasów klamrowych zamiast cudzysłowu. Dla przykładu, className="avatar"
przekaże tekst "avatar"
jako nazwę klasy CSS-owej, podczas gdy src={user.imageUrl}
odczyta wartość zmiennej javascriptowej user.imageUrl
i przekaże ją przez atrybut src
attribute:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
W nawiasach klamrowych możesz także umieszczać nieco bardziej skomplikowane wyrażenia, na przykład łączenie tekstów:
const user = { name: 'Hedy Lamarr', imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg', imageSize: 90, }; export default function Profile() { return ( <> <h1>{user.name}</h1> <img className="avatar" src={user.imageUrl} alt={'Zdjęcie ' + user.name} style={{ width: user.imageSize, height: user.imageSize }} /> </> ); }
W powyższym przykładzie style={{}}
nie jest specjalną składnią, lecz zwykłym obiektem {}
umieszczonym w nawiasach klamrowych style={ }
. Możesz używać atrybutu style
, gdy twoje style zależą od zmiennych javascriptowych.
Renderowanie warunkowe
W Reakcie nie ma specjalnej składni do zapisywania warunków. Zamiast tego możesz zastosować te same techniki, co w normalnym kodzie javascriptowym. Na przykład możesz użyć instrukcji if
, aby warunkowo dodać kod JSX-owy:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
Jeśli wolisz bardziej zwięzły kod, możesz użyć operatora warunkowego ?
. W przeciwieństwie do if
, działa on wewnątrz składni JSX:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
W przypadku gdy nie potrzebujesz gałęzi else
, możesz zastosować krótszy zapis operatora logicznego &&
:
<div>
{isLoggedIn && <AdminPanel />}
</div>
Wszystkie z powyższych metod działają także przy warunkowym określaniu atrybutów. Jeśli nie znasz się jeszcze zbyt dobrze na składni JavaScriptu, możesz zacząć od używania if...else
.
Renderowanie list
Aby wyrenderować listę komponentów, możesz użyć pętli for
lub metodę map()
dla tablic.
Dla przykładu, załóżmy, że mamy następującą tablicę produktów:
const products = [
{ title: 'Kapusta', id: 1 },
{ title: 'Czosnek', id: 2 },
{ title: 'Jabłko', id: 3 },
];
Wewnątrz twojego komponentu możesz użyć funkcji map()
, aby przekształcić tablicę produktów w tablicę elementów <li>
:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
Zwróć uwagę, że <li>
ma atrybut klucza - key
. Każdy element listy powinien posiadać ciąg znaków lub liczbę, które jednoznacznie identyfikują go spośród “rodzeństwa”. Zwykle wartość klucza wyciąga się z danych, np. ID rekordu z bazy danych. React korzysta z tych kluczy, aby później lepiej zrozumieć, co się dzieje z interfejsem, gdy dodajesz, usuwasz lub zmieniasz kolejność elementów listy.
const products = [ { title: 'Kapusta', isFruit: false, id: 1 }, { title: 'Czosnek', isFruit: false, id: 2 }, { title: 'Jabłko', isFruit: true, id: 3 }, ]; export default function ShoppingList() { const listItems = products.map(product => <li key={product.id} style={{ color: product.isFruit ? 'magenta' : 'darkgreen' }} > {product.title} </li> ); return ( <ul>{listItems}</ul> ); }
Reagowanie na zdarzenia
Możesz reagować na zdarzenia, deklarując procedurę obsługi zdarzeń wewnątrz komponentu:
function MyButton() {
function handleClick() {
alert('Czuję się kliknięty!');
}
return (
<button onClick={handleClick}>
Kliknij mnie
</button>
);
}
Zwróć uwagę, że onClick={handleClick}
nie ma na końcu nawiasów! Nie wywołuj procedury obsługi zdarzeń: musisz ją jedynie przekazać. React wywoła ją za ciebie, gdy użytkownik kliknie na przycisk.
Aktualizowanie interfejsu
Często twoje komponenty będą musiały “zapamiętać” jakąś informację i wyświetlić ją na ekranie. Na przykład, być może zechcesz zliczać, ile razy przycisk został kliknięty. Aby to zrobić, dodaj stan do komponentu.
Najpierw zaimportuj useState
z Reacta:
import { useState } from 'react';
Teraz możesz zadeklarować zmienną stanu w komponencie:
function MyButton() {
const [count, setCount] = useState(0);
// ...
Z funkcji useState
otrzymasz dwie rzeczy: aktualny stan (count
) i funkcję, która pozwoli ci go zaktualizować (setCount
). Możesz nadać im dowolne nazwy, jednak zwykle nazywa się je na wzór: [something, setSomething]
.
Przy pierwszym wyświetleniu przycisku wartość count
będzie równa 0
, ponieważ przekazaliżmy 0
do useState()
. Jeśli chcesz zmienić stan, wywołaj funkcję setCount()
i przekaż do niej nową wartość. Kliknięcie w przycisk spowoduje zwiększenie wartości licznika o 1:
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Kliknięto {count} razy
</button>
);
}
React wywoła twoją funkcję komponentu ponownie. Tym razem jednak zmienna count
będzie równa 1
. Później będzie to 2
. I tak dalej.
Jeśli wyrenderujesz ten sam komponent wielokrotnie, każdy z nich otrzyma swój własny stan. Spróbuj kliknąć na każdy z przycisków z osobna:
import { useState } from 'react'; export default function MyApp() { return ( <div> <h1>Counters that update separately</h1> <MyButton /> <MyButton /> </div> ); } function MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Kliknięto {count} razy </button> ); } export default function MyApp() { return ( <div> <h1>Liczniki, które aktualizują się niezależnie od siebie</h1> <MyButton /> <MyButton /> </div> ); }
Zwróć uwagę, że każdy z przycisków “pamięta” swoją własną wartość stanu count
i nie wpływa na inne przyciski.
Używanie hooków
Funkcje o nazwie rozpoczynającej się od use
nazywamy hookami. useState
to wbudowany hook dostarczony przez Reacta. Inne hooki znajdziesz w dokumentacji API Reacta. Możesz także stworzyć swój własny hook i wywołać w nim te istniejące.
Hooki są bardziej restrykcyjne od zwykłych funkcji. Możesz je wywołać tylko na głównym poziomie komponentu (lub innego hooka). Jeśli chcesz skorzystać z useState
w warunku lub pętli, przenieś go do nowego komponentu, a następnie wyrenderuj ten komponent.
Dzielenie danych między komponentami
W poprzednim przykładzie każdy MyButton
miał swój własny licznik count
, a gdy kliknęliśmy na któryś z przycisków, tylko count
tego przycisku ulegał zmianie:
Jednakże czasem zachodzi potrzeba, by komponenty współdzieliły dane i zawsze aktualizowały się jednocześnie.
Aby sprawić, by obydwa komponenty MyButton
wyświetlały tę samą wartość licznika count
i aktualizowały się jednocześnie, musisz przenieść stan z każdego z nich “w górę” do najbliższego rodzica, który je renderuje.
W naszym przykładzie będzie to MyApp
:
Jeśli teraz klikniesz na którykolwiek z przycisków, wartość licznika count
w MyApp
ulegnie zmianie, a co za tym idzie zmienią się liczniki w komponentach MyButton
. Oto jak możemy opisać tę zależność za pomocą kodu.
Najpierw przenieś stan do góry z MyButton
do MyApp
:
function MyButton() {
// ... przenosimy kod stąd ...
}
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Liczniki, które aktualizują się niezależnie od siebie</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
// ... we're moving code from here ...
}
Teraz przekaż stan w dół z MyApp
do każdego z komponentów MyButton
. Nie zapomnij także o obsłudze kliknięcia. Możesz przekazać informacje do MyButton
używając nawiasów klamrowych, tak jak zrobiliśmy to poprzednio na <img>
:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Liczniki, które zmieniają się jednocześnie</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
Informacja, którą przekazujesz w dół w ten sposób, nazywana jest właściwością. Teraz komponent MyApp
zawiera stan count
i procedurę obsługi zdarzenia handleClick
, które przekazuje w dół jako właściwości do każdego z przycisków.
Na koniec zmodyfikuj MyButton
tak, aby odczytywał właściwości przekazane mu przez rodzica:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Kliknięto {count} razy
</button>
);
}
Kiedy klikasz w przycisk, wywoływana jest procedura z właściwości onClick
. Właściwość onClick
dla każdego z przycisków została ustawiona w MyApp
na handleClick
, dlatego to handleClick
jest wywoływana, a co za tym idzie, wywoływany jest kod setCount(count + 1)
, który zwiększa wartość stanu count
o jeden. Nowa wartość count
jest przekazywana przez właściwość do każdego z przycisków, dzięki czemu mogą one ją wyświetlić.
Opisany tu proces nazywa się “wynoszeniem stanu w górę”. Przenosząc stan w górę umożliwiamy dzielenie go między komponentami.
import {useState} from 'react'; export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Liczniki, które aktualizują się jednocześnie</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); } function MyButton({ count, onClick }) { return ( <button onClick={onClick}> Kliknięto {count} razy </button> ); }
Następne kroki
Znasz już podstawy pisania kodu reactowego!
Przejdź do rozdziału pt. Myślenie reactowe, aby poczuć, co w praktyce oznacza tworzenie UI w Reakcie.