Witaj z powrotem w Kosmicznej Stacji, pilotze! W tym module poznamy zaawansowane wzorce projektowe React, które pomogą Ci budować skalowalne i elastyczne aplikację. Zaczynamy od najważniejszej zasady -- kompozycji.
Wyobraź sobie, że budujesz statek kosmiczny. Masz dwa podejścia:
React celowo nie wspiera dziedziczenia komponentów. Zamiast tego daje nam potężne narzędzia kompozycji.
Zamiast tworzyć klasy bazowe i podklasy, w React tworzymy komponent ogólny i specjalizujemy go przez propsy:
1// Ogólny komponent przycisku
2function SpaceButton({ variant, size, children, onClick }) {
3 const baseStyle = "space-btn";
4 const variantStyle = variant === "danger" ? "btn-danger" : "btn-primary";
5 const sizeStyle = size === "large" ? "btn-lg" : "btn-sm";
6
7 return (
8 <button className={`${baseStyle} ${variantStyle} ${sizeStyle}`} onClick={onClick}>
9 {children}
10 </button>
11 );
12}
13
14// Specjalizacja przez props -- NIE przez dziedziczenie
15function LaunchButton({ onClick }) {
16 return (
17 <SpaceButton variant="danger" size="large" onClick={onClick}>
18 LAUNCH
19 </SpaceButton>
20 );
21}React pozwala komponentom nie wiedzieć z góry, jakie będą ich dzieci. Używamy
children do tworzenia kontenerów:1// Komponent-kontener (nie wie, co będzie w środku)
2function SpacePanel({ title, children }) {
3 return (
4 <div className="space-panel">
5 <div className="panel-header">
6 <h2>{title}</h2>
7 </div>
8 <div className="panel-body">
9 {children}
10 </div>
11 </div>
12 );
13}
14
15// Użycie -- wstawiamy dowolną zawartość
16function Dashboard() {
17 return (
18 <SpacePanel title="Status misji">
19 <p>Paliwo: 87%</p>
20 <p>Prędkość: 12 000 km/s</p>
21 </SpacePanel>
22 );
23}Gdy jeden
children nie wystarczy, możemy użyć wielu propsów jako slotów:1function SpaceLayout({ header, sidebar, children }) {
2 return (
3 <div className="layout">
4 <header className="layout-header">{header}</header>
5 <aside className="layout-sidebar">{sidebar}</aside>
6 <main className="layout-main">{children}</main>
7 </div>
8 );
9}
10
11function MissionControl() {
12 return (
13 <SpaceLayout
14 header={<Navigation />}
15 sidebar={<CrewList />}
16 >
17 <MissionMap />
18 <StatusPanel />
19 </SpaceLayout>
20 );
21}Render Props to wzorzec, w którym komponent przyjmuje funkcje jako prop i uzywa jej do renderowania. Daje to pelna kontrole nad tym, co zostanie wyswietlone:
1function DataFetcher({ url, render }) {
2 const [data, setData] = useState(null);
3 const [loading, setLoading] = useState(true);
4
5 useEffect(() => {
6 fetch(url)
7 .then(res => res.json())
8 .then(d => { setData(d); setLoading(false); });
9 }, [url]);
10
11 return render({ data, loading });
12}
13
14// Uzycie -- TY decydujesz jak wyswietlic dane
15function MissionPage() {
16 return (
17 <DataFetcher
18 url="/api/missions"
19 render={({ data, loading }) => {
20 if (loading) return <p>Ladowanie misji...</p>;
21 return <MissionList missions={data} />;
22 }}
23 />
24 );
25}Render Props pozwala na duza elastycznosc, ale dzis czesciej zastepowalny przez custom hooks, które daja ten sam efekt w prostszej formie.
| Cecha | Dziedziczenie | Kompozycja | |-------|---------------|------------| | Elastyczność | Sztywna hierarchia | Swobodne łączenie | | Reużywalność | Ograniczona | Wysoka | | Testowanie | Trudne (zależności) | Łatwe (izolacja) | | React support | Brak | Pełne |
Kluczowa zasada: Jeśli chcesz ponownie użyć logiki między komponentami, użyj kompozycji, nie dziedziczenia. React został zaprojektowany z mysla o kompozycji -- kazdy komponent to niezalezny modul, który mozna swobodnie laczyc z innymi. To jak budowanie statku kosmicznego z wymiennych czesci -- kazda czesc dziala samodzielnie, ale razem tworza potezna maszyne.