React / Patterns

Wzorce projektowe React

Compound Components, Custom Hooks, Provider Pattern i Error Boundaries — najważniejsze wzorce dla skalowalnych aplikacji React.

Compound
Wspólny stan
Custom Hooks
Reużywalna logika
Provider
Globalny stan
Error Boundary
Obsługa błędów

6 wzorców projektowych React

Compound Components, Custom Hooks, Render Props, HOC, Provider i Error Boundary — kiedy stosować każdy wzorzec i jakie problemy rozwiązuje.

WzorzecCelImplementacjaPrzykładKiedy
Compound ComponentsElastyczny, powiązany UIContext + Root/Child componentsSelect, Tabs, Accordion, DialogKomponenty z powiązanym stanem, shadcn/ui
Custom HooksReużywalna logika stanowauseXxx() functionuseLocalStorage, useDebounce, useFetchTa sama logika w 2+ komponentach
Render PropsDzielenie logiki renderowaniaprop children / render as functionreact-query renderProp, FormikRzadko — hooks są lepsze
HOCOwijanie komponentówwithXxx(Component)withAuth, connect (Redux)Class components, biblioteki legacy
Provider PatternGlobalny stan/DIContext.Provider + useXxx()AuthProvider, ThemeProviderGlobal state bez prop drilling
Error BoundaryObsługa błędów renderowaniaclass ErrorBoundary lub react-error-boundaryFallback UI, retry logicZawsze owijaj sekcje UI

Często zadawane pytania

Compound Components Pattern — co to jest i jak implementować?

Compound Components: wzorzec gdzie kilka komponentów współdzieli ukryty stan przez Context. Przykład z HTML: select + option (natywne compound components). React implementacja: Select.Root, Select.Trigger, Select.Value, Select.Content, Select.Item — jak Radix UI. Implementacja: const SelectContext = createContext(). SelectRoot provider + context. SelectTrigger, SelectItem consumerzy kontekstu. Użycie: Select.Root value={value} onChange={setValue} -> Select.Trigger -> Select.Content -> Select.Item. Zalety: elastyczny layout (user decyduje gdzie co). Brak prop drilling. Czytelna struktura. Wbudowany state management. Przykład Tabs: Tabs.Root + Tabs.List + Tabs.Tab + Tabs.Content. Tabs.Root: activeTab state + context. Tabs.Tab: onClick -> setActiveTab. Tabs.Content: render gdy activeTab === id. shadcn/ui bazuje na tym wzorcu (Radix UI). Wariant z React.Children: React.cloneElement(child, {extraProp}). Mniej elastyczny (hierarchia wymagana). Context lepszy. Implicit state sharing: user nie musi przekazywać state między komponentami. Magicznie się komunikują przez context. Biblioteki: Radix UI, Headless UI — compound components. Reach UI — pierwotny popularyzator wzorca.

Custom Hooks — jak pisać i kiedy wyodrębniać logikę?

Custom Hooks: funkcje zaczynające od 'use' korzystające z wbudowanych hooków. Wyodrębniają logikę stanową z komponentów. Cel: reużywalność logiki. Separacja of concerns. Testowalność (hook oddzielnie od UI). Przykłady custom hooks: useLocalStorage: useState + useEffect + localStorage. Przechowuje stan w localStorage. Synchronizacja między tabs (storage event). useDebounce: useState + useEffect z setTimeout. Opóźnia aktualizację wartości. Dla search inputs. useMediaQuery: useState + useEffect z matchMedia. Reaguje na breakpoints. SSR-safe. useFetch: useState + useEffect + AbortController. Generyczny data fetching. Cancel on unmount. useIntersectionObserver: useState + useRef + IntersectionObserver. Lazy loading. Infinite scroll. useEventListener: useEffect z addEventListener. Automatyczne cleanup. Typed events. usePrevious: useRef — przechowuj poprzednią wartość. useClickOutside: useRef + useEventListener. Zamknij dropdown po kliknięciu poza. useHotkeys: keydown event. Skróty klawiszowe. react-hotkeys-hook. Reguły hooków: tylko na top level (nie w if/loop). Tylko w React functions (component lub hook). Kiedy wyodrębniać: ta sama logika w 2+ komponentach. Logika ukrywa szczegóły implementacji. Logika chcesz testować oddzielnie.

Render Props i Higher-Order Components — stare wzorce vs hooks?

Render Props (2017): komponent przyjmuje funkcję jako prop. Funkcja zwraca React elements. Pozwala współdzielić logikę stanową. Przykład: MouseTracker render={({x, y}) => div}. Aktualnie: children as function (prop children jako funkcja). Hooks zastąpiły render props dla większości use cases. Ale nadal używane w: react-query (v4 ma render prop API). Formik render prop. Komputacja nad tablicami danych. Higher-Order Components (HOC) (2016): funkcja przyjmuje komponent, zwraca nowy. withAuth(Component) — komponent z auth check. withLoading(Component) — komponent z loading state. Problemy HOC: wrapper hell (wielokrotne owijanie). Nieczytelny displayName. Props collision. Hooks zastąpiły HOC dla większości use cases. Nadal używane: connect() w Redux (stary API). withRouter w React Router 5. HOC dla class components. State Machine HOC (XState) — withMachine. Composition pattern (2024): zamiast HOC używaj kompozycji. ComposedButton = withTracking(withTheme(Button)). Stało się: const Button = () => {const theme = useTheme(); const track = useTracking(); ...}. Provider pattern: Context Provider + custom hook. AuthProvider + useAuth(). ThemeProvider + useTheme(). Container/Presentational (stary): Container — logika. Presentational — UI. Hooks sprawiły że to mniej ważne. Ale nadal wartościowy pattern konceptualnie.

Performance patterns — memo, useMemo, useCallback i lazy loading?

React.memo: opakowuje komponent. Rerenderuje tylko gdy props zmieniają się. Domyślne porównanie: shallow equality. Custom: React.memo(Component, (prev, next) => prev.id === next.id). Kiedy używaj: komponent drogi (wiele dzieci, obliczenia). Komponent renderuje się często z tymi samymi props. Kiedy NIE: komponent tani. Props zawsze różne. useMemo: zapamiętuje wynik obliczeń. const sorted = useMemo(() => items.sort(...), [items]). Uwaga: premature optimization. Memoizacja ma koszt. Używaj tylko gdy obliczenie jest drogie. useCallback: zapamiętuje funkcję. Stabilna referencja. Ważne gdy przekazujesz do React.memo dziecka. const handleClick = useCallback(() => {...}, [deps]). React.lazy + Suspense: dynamic import dla code splitting. const HeavyComponent = lazy(() => import('./Heavy')). Suspense fallback={div}. Route-based code splitting (najważniejszy use case). Component-level splitting (mniej potrzebny). startTransition: oznacz update jako non-urgent. Np. search input — wyniki nieistotne do zakończenia typing. isPending z useTransition — loading state. Virtualization: react-window, react-virtual (TanStack Virtual). Renderuj tylko widoczne elementy. 10,000 wierszy listy — tylko 20 renderowanych. React Compiler (RC 2024): automatyczna memoizacja. Zastąpi manualne useMemo/useCallback. React 19 + compiler = mniej boilerplate.

Error Boundaries i Suspense — obsługa błędów i asynchroniczności?

Error Boundaries: class components łapiące błędy potomków (tylko class, nie hooks). componentDidCatch(error, info). getDerivedStateFromError(error). Kiedy łapie: render time errors. Constructor errors. Lifecycle method errors. Kiedy NIE łapie: async errors (useEffect, event handlers). SSR errors. Błędy w samym boundary. Implementacja: class ErrorBoundary extends React.Component {state = {hasError: false}. static getDerivedStateFromError() {return {hasError: true}}. render() {if (this.state.hasError) return fallback. return children}}. react-error-boundary: biblioteka ułatwiająca (hooks-friendly). ErrorBoundary + fallbackRender. useErrorBoundary — imperatively throw. resetErrorBoundary — reset po błędzie. Suspense (React 18+): obsługa asynchronicznych zasobów. fallback={Spinner} — podczas ładowania. Działa z lazy (code splitting). Działa z async data (TanStack Query, Relay, SWR — eksperymentalnie). Nested Suspense: każdy ma własny fallback. Granularne loading states. Streaming SSR + Suspense: server streams HTML. Suspense boundaries wysyłane gdy dane gotowe. Szybszy TTFB. use() hook (React 19): use(promise) — zawiesza komponent. use(context) — jak useContext ale może być warunkowy. Async Server Components (Next.js): async function Page() {const data = await fetchData(). return div}. Serwer obsługuje async. Klient dostaje statyczny HTML.

Kontakt

Skontaktuj się z nami

Porozmawiajmy o Twoim projekcie. Bezpłatna wycena w ciągu 24 godzin.

Wyślij zapytanie

Bezpłatna wycena w 24h
Bez zobowiązań
Indywidualne podejście
Ekspresowa realizacja

Telefon

+48 790 814 814

Pon-Pt: 9:00 - 18:00

Email

adam@fotz.pl

Odpowiadamy w ciągu 24h

Adres rejestrowy

Poznańska 117/11

62-023 Kamionki · obsługa zdalna

Godziny pracy

Pon - Pt9:00 - 18:00
Sob - NdzZamknięte

Wolisz porozmawiać?

Zadzwoń teraz i porozmawiaj z naszym specjalistą o Twoim projekcie.

Zadzwoń teraz