Lekcja 8: Renderowanie Warunkowe
W aplikacjach React często potrzebujemy wyświetlać różne elementy interfejsu w zależności od określonych warunków, takich jak stan aplikacji, dane użytkownika czy propsy. React oferuje kilka elastycznych sposobów na realizację renderowania warunkowego.
1. Instrukcja `if` wewnątrz Komponentu
Możemy używać standardowych instrukcji warunkowych JavaScript (if/else
) przed zwróceniem JSX z komponentu, aby zdecydować, co ma zostać wyrenderowane.
import React from \'react\';
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Witaj ponownie!</h1>;
} else {
return <h1>Proszę się zalogować.</h1>;
}
}
function App() {
const [loggedIn, setLoggedIn] = React.useState(false);
return (
<div>
<Greeting isLoggedIn={loggedIn} />
<button onClick={() => setLoggedIn(!loggedIn)}>
{loggedIn ? \'Wyloguj\' : \'Zaloguj\'}
</button>
</div>
);
}
export default App;
Możemy również przypisać wynik warunku do zmiennej i użyć jej w JSX.
function LoginStatus({ isLoggedIn }) {
let statusMessage;
if (isLoggedIn) {
statusMessage = <p>Jesteś zalogowany.</p>;
} else {
statusMessage = <p>Nie jesteś zalogowany.</p>;
}
return <div>{statusMessage}</div>;
}
2. Operator Trójargumentowy (Warunkowy) `? :`
Operator trójargumentowy (condition ? valueIfTrue : valueIfFalse
) jest bardzo przydatny do osadzania prostych warunków bezpośrednio w JSX. Jest to często bardziej zwięzłe niż użycie if/else
poza JSX.
import React, { useState } from \'react\';
function Mailbox({ unreadMessages }) {
const count = unreadMessages.length;
return (
<div>
<h1>Skrzynka odbiorcza</h1>
{count > 0 ? (
<h2>
Masz {count} nieprzeczytanych {count === 1 ? \'wiadomość\' : \'wiadomości\'}.
</h2>
) : (
<p>Brak nowych wiadomości.</p>
)}
</div>
);
}
function App() {
const [messages, setMessages] = useState([\'Re: Spotkanie\', \'Pilne!\']);
return <Mailbox unreadMessages={messages} />;
}
export default App;
3. Operator Logiczny AND `&&`
Operator &&
jest użyteczny, gdy chcemy wyrenderować coś tylko wtedy, gdy warunek jest prawdziwy, a w przeciwnym razie nie renderować niczego. Działa to, ponieważ w JavaScript true && expression
zawsze zwraca expression
, a false && expression
zawsze zwraca false
. React nie renderuje wartości false
, null
, undefined
ani true
.
function WarningBanner({ showWarning }) {
return (
<div>
{showWarning &&
<div className="warning">
Uwaga! To jest ostrzeżenie.
</div>
}
<p>Główna treść strony...</p>
</div>
);
}
function App() {
const [displayWarning, setDisplayWarning] = useState(true);
return (
<div>
<WarningBanner showWarning={displayWarning} />
<button onClick={() => setDisplayWarning(!displayWarning)}>
{displayWarning ? \'Ukryj\' : \'Pokaż\'} ostrzeżenie
</button>
</div>
);
}
Uwaga: Uważaj na wartości "fałszywe" (falsy) inne niż false
, np. 0
. Wyrażenie count && <Element />
, gdzie count
wynosi 0
, spowoduje wyrenderowanie 0
w DOM, co zazwyczaj nie jest pożądane. W takich przypadkach lepiej użyć operatora trójargumentowego: count > 0 ? <Element /> : null
.
4. Zapobieganie Renderowaniu Komponentu (zwracanie `null`)
Jeśli chcesz całkowicie zapobiec renderowaniu komponentu pod pewnym warunkiem, możesz sprawić, by zwracał on null
.
function AdminPanel({ isAdmin }) {
if (!isAdmin) {
return null; // Nie renderuj niczego, jeśli użytkownik nie jest adminem
}
return (
<div className="admin-panel">
<h2>Panel Administratora</h2>
{/* ... zawartość panelu */}
</div>
);
}
function App() {
const [userRole, setUserRole] = useState(\'user\'); // \'user\' lub \'admin\'
return (
<div>
<p>Witaj, użytkowniku!</p>
<AdminPanel isAdmin={userRole === \'admin\'} />
{/* Przycisk do zmiany roli dla demonstracji */}
<button onClick={() => setUserRole(userRole === \'admin\' ? \'user\' : \'admin\')}>
Zmień rolę
</button>
</div>
);
}
Zwrócenie null
z metody render
(w komponentach klasowych) lub z komponentu funkcyjnego nie wpływa na uruchamianie metod cyklu życia komponentu (lub efektów w useEffect
). Po prostu nic nie jest renderowane do DOM.
Wybór Odpowiedniej Metody
- Użyj
if/else
poza JSX dla bardziej złożonych warunków lub gdy chcesz zwrócić zupełnie różne struktury JSX. - Użyj operatora trójargumentowego
? :
wewnątrz JSX dla prostych warunków typu "jeśli A, to X, w przeciwnym razie Y". - Użyj operatora logicznego
&&
wewnątrz JSX, gdy chcesz renderować coś tylko wtedy, gdy warunek jest prawdziwy ( "jeśli A, to X, w przeciwnym razie nic"). - Zwróć
null
z komponentu, aby całkowicie zapobiec jego renderowaniu.
Ćwiczenie praktyczne
Pokaż rozwiązanie
// src/LoadingStatus.jsx
import React, { useState } from \'react\';
function LoadingStatus() {
const [status, setStatus] = useState(\'idle\'); // \'idle\', \'loading\', \'success\', \'error\'
let content;
if (status === \'loading\') {
content = <p>Ładowanie danych... Proszę czekać.</p>;
} else if (status === \'success\') {
content = <p style={{ color: \'green\' }}>Dane zostały pomyślnie załadowane!</p>;
} else if (status === \'error\') {
content = <p style={{ color: \'red\' }}>Wystąpił błąd podczas ładowania danych.</p>;
} else { // idle
content = <p>Kliknij przycisk, aby rozpocząć ładowanie.</p>;
}
return (
<div>
<h2>Status Ładowania</h2>
{content}
<div>
<button onClick={() => setStatus(\'loading\')} disabled={status === \'loading\'}>
Rozpocznij ładowanie
</button>
<button onClick={() => setStatus(\'success\')} disabled={status !== \'loading\'}>
Symuluj Sukces
</button>
<button onClick={() => setStatus(\'error\')} disabled={status !== \'loading\'}>
Symuluj Błąd
</button>
<button onClick={() => setStatus(\'idle\')} disabled={status === \'idle\'}>
Resetuj
</button>
</div>
</div>
);
}
export default LoadingStatus;
// W App.jsx
import React from \'react\';
import LoadingStatus from \'./LoadingStatus\";
function App() {
return (
<div>
<LoadingStatus />
</div>
);
}
export default App;
Cel: Stworzyć komponent, który wyświetla różne komunikaty w zależności od statusu ładowania danych (np. "Ładowanie...", "Dane załadowane!", "Błąd ładowania.").
Kroki:
- Stwórz komponent funkcyjny
LoadingStatus
. - Użyj
useState
do przechowywania statusu ładowania, np.status
, który może przyjmować wartości:\'idle\'
,\'loading\'
,\'success\'
,\'error\'
. Zainicjuj go na\'idle\'
. - Dodaj przyciski symulujące rozpoczęcie ładowania, sukces i błąd, które będą zmieniać stan
status
. - W komponencie
LoadingStatus
użyj renderowania warunkowego (np.if/else if/else
lub zagnieżdżonych operatorów trójargumentowych), aby wyświetlić odpowiedni komunikat w zależności od wartości stanustatus
. - Użyj komponentu
LoadingStatus
wApp.jsx
.
Zadanie do samodzielnego wykonania
Stwórz komponent UserProfileCard
, który przyjmuje props user
(obiekt z polami name
, email
, isAdmin
- boolean). Komponent powinien:
- Wyświetlać imię użytkownika (
user.name
). - Wyświetlać email użytkownika (
user.email
). - Jeśli
user.isAdmin
jesttrue
, wyświetlić dodatkowo odznakę "(Admin)" obok imienia (użyj operatora&&
). - Jeśli obiekt
user
nie zostanie przekazany (propsuser
jestnull
lubundefined
), komponent powinien zwrócićnull
(nie renderować niczego). - Przetestuj komponent w
App.jsx
, przekazując różne obiektyuser
(w tymnull
).
FAQ - Renderowanie Warunkowe
Czy mogę używać `switch` do renderowania warunkowego?
Tak, instrukcja `switch` może być używana poza JSX do decydowania, który element lub komponent zwrócić, podobnie jak `if/else`. Nie można jej jednak używać bezpośrednio wewnątrz nawiasów klamrowych `{}` w JSX, ponieważ `switch` jest instrukcją, a nie wyrażeniem.
Która metoda renderowania warunkowego jest najlepsza?
Nie ma jednej "najlepszej" metody. Wybór zależy od złożoności warunku i preferencji czytelności. Proste warunki inline dobrze obsługują operatory `? :` i `&&`. Bardziej złożona logika lub zwracanie zupełnie innych struktur często lepiej wygląda z użyciem `if/else` lub `switch` przed instrukcją `return`.
Czy renderowanie warunkowe wpływa na wydajność?
Samo renderowanie warunkowe jest bardzo wydajne. React efektywnie aktualizuje DOM tylko wtedy, gdy wynik warunku się zmienia. Problemy z wydajnością mogą pojawić się, jeśli warunki są bardzo skomplikowane lub jeśli zmiana warunku powoduje renderowanie bardzo dużych i złożonych drzew komponentów.
Jak warunkowo dodawać atrybuty do elementu JSX?
Można użyć operatora trójargumentowego lub `&&` do warunkowego ustawiania wartości atrybutu. Jeśli warunek jest fałszywy, można przypisać `null` lub `undefined`, co spowoduje, że React pominie ten atrybut. Dla atrybutów typu boolean (np. `disabled`), można przekazać `true` lub `false`.
Czy mogę renderować różne komponenty w zależności od warunku?
Tak, jest to bardzo częsty wzorzec. Możesz użyć dowolnej metody renderowania warunkowego, aby zdecydować, który komponent (np. `` czy ``) ma zostać wyrenderowany w danym miejscu.
Co się stanie, gdy użyję `0 &&`?
Ponieważ `0` jest wartością "falsy" w JavaScript, całe wyrażenie `0 && ` zwróci `0`. React wyrenderuje `0` jako tekst w DOM, co zazwyczaj nie jest pożądane. Aby uniknąć renderowania czegokolwiek w takim przypadku, użyj jawnego porównania: `count > 0 && ` lub operatora trójargumentowego: `count ? : null`.
Czy zwrócenie `null` z komponentu jest tym samym co nie wywołanie funkcji renderującej?
Nie do końca. Komponent nadal jest montowany i przechodzi przez swój cykl życia (Hooki `useState` i `useEffect` nadal działają). Zwrócenie `null` jedynie informuje React, aby nie renderował żadnego wyjścia DOM dla tego komponentu w danym cyklu renderowania.