← Wszystkie tematy W 13% ogłoszeń · 6 z 47 ogłoszeń frontend React

Dane serwerowe i cache

Lodówka z jedzeniem, które ma datę ważności

Dane serwerowe i cache pojawiają się w 6 z 47 ogłoszeń, zwykle jako TanStack Query, React Query lub SWR. To częsty temat, gdy rozmowa schodzi na „jak pobierasz dane w React”.

Opanowane 0 z 4 pytań

Co piszą w ogłoszeniach

Scena pierwsza · staleTime i gcTime

Lodówka z datą ważności

Dane z serwera to jedzenie ze sklepu. Przynosisz je do lodówki (cache), żeby nie biegać do sklepu przy każdym głodzie. Na każdym produkcie jest data świeżości (staleTime): do niej jesz bez pytania. Po niej jedzenie jest nieświeże: możesz je zjeść od razu, ale w tle ktoś biegnie po nowe. Jeśli nikt nie je czegoś przez dłuższy czas, mama wyrzuca to z lodówki (gcTime). Wchodź na ekran, wychodź i przewijaj czas.

Lodówka (cache) pusto
Zegar: 0 s
ekran zamknięty
Sieć: spokój

Wejdź na ekran. gcTime wynosi tu 60 s.

Scena druga · optimistic update

Serduszko od razu

Klikasz serduszko pod zdjęciem. Możesz poczekać na odpowiedź serwera i dopiero wtedy pokazać serduszko. Albo od razu je zapalić, bo prawie zawsze się udaje. Gdy jednak serwer powie „nie”, trzeba grzecznie wycofać zmianę i powiedzieć o tym użytkownikowi.

Kliknij serduszko w obu trybach.

Porównajmy

fetch w useEffect czy TanStack Query?

fetch w useEffectTanStack Query
Lodówka Brak. Każde wejście to bieg do sklepu.Każdy mount robi nowe żądanie. Jest, wspólna dla całej aplikacji.Cache po queryKey, deduplikacja równoległych żądań.
Stany Piszesz sam loading, error, data.Trzy useState i łatwo o niemożliwe kombinacje. Gotowe.isPending, isError, isFetching, data.
Nieświeże jedzenie Nikt nie pilnuje dat.Dane się starzeją, odświeżasz ręcznie. Samo odświeża w tle.staleTime, refetch przy powrocie do karty i po reconnect.
Po zmianie danych Ręczne aktualizowanie stanu w kilku miejscach. Unieważniasz klucz i wszystko się odświeża.invalidateQueries, setQueryData, optimistic update w onMutate.
Wyścigi i anulowanie Sam pilnujesz AbortController i flagi.Race conditions przy szybkiej zmianie filtrów. Wbudowane.signal w queryFn, odpowiedź zawsze dla aktualnego klucza.

Data świeżości

staleTime: jak długo jesz z lodówki bez pytania sklepu.

Sprzątanie

gcTime: jak długo nieużywane jedzenie leży, zanim mama je wyrzuci.

Najpierw serduszko

Optimistic update: zmień od razu, zapamiętaj stan sprzed zmiany, przy błędzie przywróć.

Sprawdź się

Pytania z rozmów

Najpierw odpowiedz na głos, dopiero potem rozwiń odpowiedź.

  1. Co daje TanStack Query w porównaniu z fetch w useEffect?

    Moja odpowiedź

    Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

    Pokaż odpowiedź

    Dla przedszkolaka: Zamiast biec do sklepu za każdym razem, gdy zgłodniejesz, masz lodówkę, która pamięta, co kupiłeś, i sama sprawdza, czy jedzenie jest jeszcze świeże.

    Na rozmowę: Cache po queryKey wspólny dla całej aplikacji, deduplikacja równoległych żądań, gotowe stany (isPending, isError, isFetching), stale-while-revalidate, refetch przy powrocie do karty i po odzyskaniu sieci, retry z backoffem, anulowanie przez signal, paginacja i infinite query, mutacje z invalidateQueries i optimistic update, DevTools. W useEffect każdą z tych rzeczy piszesz sam i łatwo o race condition albo pętlę żądań.

    Umiem?
    Zapytaj Claude RozwińPrzepytaj mniePytania pogłębiające
  2. staleTime vs gcTime: czym się różnią?

    Moja odpowiedź

    Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

    Pokaż odpowiedź

    Dla przedszkolaka: staleTime to data świeżości na jedzeniu: do niej jesz bez pytania. gcTime mówi, jak długo nieużywane jedzenie leży w lodówce, zanim mama je wyrzuci.

    Na rozmowę: staleTime (domyślnie 0) to czas, przez jaki dane uznaje się za świeże: query nie odświeża się przy montowaniu ani focusie. Po nim dane są stale: nadal pokazywane z cache od razu, ale w tle leci refetch. gcTime (dawniej cacheTime, domyślnie 5 min) liczy się od momentu, gdy nikt nie obserwuje query, a po nim wpis jest usuwany z cache. Dla rzadko zmiennych danych (słowniki, konfiguracja) podnoszę staleTime, żeby nie zasypywać API żądaniami.

    Umiem?
    Zapytaj Claude RozwińPrzepytaj mniePytania pogłębiające
  3. Optimistic update: jak go zrobić i jak wycofać przy błędzie?

    Moja odpowiedź

    Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

    Pokaż odpowiedź

    Dla przedszkolaka: Zapalasz serduszko od razu, bo prawie zawsze się udaje. Ale zapamiętujesz, jak było wcześniej, żeby móc to przywrócić, gdy serwer powie „nie”.

    Na rozmowę: W useMutation: onMutate anuluje trwające zapytania (cancelQueries), zapisuje poprzedni stan (getQueryData), ustawia nowy przez setQueryData i zwraca kontekst z kopią. onError przywraca kopię z kontekstu i pokazuje komunikat. onSettled robi invalidateQueries, żeby zsynchronizować się z serwerem. Prostsza wersja w v5: pokazanie zmiennych mutacji (variables) w UI podczas isPending. W React 19 jest też useOptimistic. Stosuję tam, gdzie błąd jest rzadki i łatwo go cofnąć (like, zmiana kolejności), a nie przy płatnościach.

    Umiem?
    Zapytaj Claude RozwińPrzepytaj mniePytania pogłębiające
  4. Jak zorganizować klucze zapytań (queryKey) i unieważnianie po mutacji?

    Moja odpowiedź

    Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

    Pokaż odpowiedź

    Dla przedszkolaka: Każda półka w lodówce ma etykietę, np. „lizaki, strona 2”. Gdy dokupisz lizaki, wyrzucasz wszystko z półki „lizaki”, a reszta lodówki zostaje.

    Na rozmowę: Klucze hierarchiczne jako tablice: ['products'], ['products', 'list', filters], ['products', 'detail', id]. Najlepiej przez fabrykę kluczy (productKeys.detail(id)), żeby nie literówkować. Po mutacji invalidateQueries({ queryKey: ['products'] }) unieważnia wszystko pod prefiksem, a aktywne zapytania odświeżą się same. Gdy odpowiedź mutacji zawiera nowy obiekt, setQueryData oszczędza dodatkowe żądanie. Filtry trzymam w kluczu, więc zmiana filtra to nowy wpis w cache.

    Umiem?
    Zapytaj Claude RozwińPrzepytaj mniePytania pogłębiające
Poziom wyżej

Wersja dla seniora

Tak wyglądają pytania na seniora i leada: nie ma jednej dobrej odpowiedzi, liczy się to, jak ważysz kompromisy i czy mówisz o skali, ryzyku i ludziach.

Przypadek 1

Po zmianie zamówienia lista, szczegóły i licznik pokazują różne dane

Duży panel na TanStack Query ma 80 zapytań. Klucze piszą wszyscy ręcznie jako tablice stringów. Po edycji zamówienia odświeża się szczegół, ale lista i licznik w nagłówku pokazują stare wartości, a w innym miejscu ktoś wywołuje invalidateQueries() bez argumentów i panel odpytuje wszystko naraz.

Zanim rozwiniesz: powiedz na głos, jak byś to rozwiązał, i nazwij co najmniej jeden kompromis.

Moje rozwiązanie

Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

Pokaż, czego szuka rekruter, i modelową odpowiedź

Co sprawdza rekruter

  • Czy umiesz zaprojektować hierarchię kluczy
  • Czy wiesz, jak precyzyjnie invalidować po mutacji
  • Czy proponujesz konwencję, którą zespół utrzyma

Odpowiedź seniora

Wprowadzam fabrykę kluczy per domena: orderKeys.all = ['orders'], lists() = [...all, 'list'], list(filters) = [...lists(), filters], details() i detail(id). Najlepiej razem z queryOptions, żeby klucz, funkcja pobierająca i typ były zdefiniowane w jednym miejscu i używane w useQuery, prefetchu i invalidacji.

Po mutacji: setQueryData dla szczegółu z odpowiedzi serwera (bez dodatkowego żądania), invalidateQueries({ queryKey: orderKeys.lists() }) dla wszystkich list niezależnie od filtrów i osobno licznik, który też jest pod orderKeys. Logikę invalidacji trzymam w hooku mutacji (useUpdateOrder), nie w komponentach. Dla powiązań między domenami (zamówienie zmienia stan magazynu) można użyć meta w mutacji i globalnego onSuccess w MutationCache.

Konwencję utrwalam regułą ESLint @tanstack/eslint-plugin-query i code review. Globalne invalidateQueries() bez klucza zabraniam.

Typowe wpadki

  • Odświeżanie wszystkiego po każdej mutacji
  • Klucze jako stringi rozsiane po komponentach
  • Kopiowanie danych z query do useState, przez co się rozjeżdżają

Dopytają o

  • Kiedy setQueryData, a kiedy invalidateQueries?
  • Jak obsłużysz invalidację, gdy zmianę zrobił inny użytkownik?
  • Jak przetestujesz hook mutacji z invalidacją?
Zapytaj Claude Rozwiń caseZagraj interviewera
Przypadek 2

Ceny i stany magazynowe na żywo przez WebSocket

Panel handlowca pokazuje listę 2 tysięcy produktów z cenami i stanami. Serwer wysyła przez WebSocket kilkaset zmian na sekundę. Obecnie każda wiadomość robi refetch całej listy i przeglądarka się dusi.

Zanim rozwiniesz: powiedz na głos, jak byś to rozwiązał, i nazwij co najmniej jeden kompromis.

Moje rozwiązanie

Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

Pokaż, czego szuka rekruter, i modelową odpowiedź

Co sprawdza rekruter

  • Czy umiesz połączyć dane real-time z cache zapytań
  • Czy myślisz o przepustowości i liczbie renderów
  • Czy obsługujesz zerwanie połączenia i spójność danych

Odpowiedź seniora

Lista ładuje się zwykłym zapytaniem, a WebSocket tylko aktualizuje cache, bez refetchu. Zdarzenia z gniazda zbieram w buforze i raz na klatkę albo co 200 ms robię jedną aktualizację: queryClient.setQueryData(productKeys.list(f), old => zastosuj zmiany po id). Dane przechowuję tak, żeby update był tani (mapa po id albo znormalizowane szczegóły), a staleTime ustawiam na Infinity, bo świeżość zapewnia gniazdo.

Rendering: wirtualizacja listy i wiersze memo z selektorem po id, żeby zmiana ceny jednego produktu renderowała jeden wiersz. Przy ogromnym ruchu warto rozważyć trzymanie strumienia poza Reactem i subskrypcję per wiersz (useSyncExternalStore).

Spójność: zdarzenia mają numer wersji lub sekwencji, starsze ignoruję. Po zerwaniu i ponownym połączeniu robię jeden invalidateQueries, bo mogłem zgubić zdarzenia. Gdy karta jest w tle, mogę się wypisać z gniazda i odświeżyć przy powrocie.

Typowe wpadki

  • Refetch po każdej wiadomości
  • setQueryData na każde zdarzenie osobno, setki renderów na sekundę
  • Brak obsługi zgubionych zdarzeń po reconnect

Dopytają o

  • Jak pokażesz użytkownikowi, że dane są chwilowo nieaktualne?
  • SSE czy WebSocket w tym przypadku?
  • Jak przetestujesz zachowanie przy kolejności zdarzeń poza porządkiem?
Zapytaj Claude Rozwiń caseZagraj interviewera
Przypadek 3

Strona produktu z Next.js: dane pobierane dwa razy i mrugające spinnery

App Router w Next.js i TanStack Query. Strona produktu pobiera dane na serwerze w Server Component, a potem komponent klienta robi to samo zapytanie i pokazuje spinner na moment. Do tego zalogowani użytkownicy czasem widzą cudzą listę ulubionych.

Zanim rozwiniesz: powiedz na głos, jak byś to rozwiązał, i nazwij co najmniej jeden kompromis.

Moje rozwiązanie

Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

Pokaż, czego szuka rekruter, i modelową odpowiedź

Co sprawdza rekruter

  • Czy znasz prefetching na serwerze i hydratację cache
  • Czy rozumiesz cykl życia QueryClient na serwerze
  • Czy widzisz problem bezpieczeństwa współdzielonego cache

Odpowiedź seniora

Podwójne pobieranie: na serwerze tworzę QueryClient, robię prefetchQuery z tymi samymi queryOptions co na kliencie, a wynik przekazuję przez dehydrate i HydrationBoundary. Komponent klienta dostaje dane z cache bez requestu, pod warunkiem że klucze są identyczne i staleTime jest większy od zera (np. 60 s), inaczej od razu zrobi refetch.

Cudze dane to najpoważniejszy problem: QueryClient na serwerze był utworzony raz na poziomie modułu i współdzielony między żądaniami różnych użytkowników. Na serwerze klient musi być tworzony na każde żądanie (np. funkcja getQueryClient z cache() w React), a na kliencie jeden na sesję przeglądarki.

Dodatkowo dzielę dane: publiczne dane produktu mogą korzystać z cache Next.js i CDN, a dane użytkownika pobieram bez cache po stronie serwera albo dopiero na kliencie. Streamuję wolne części przez Suspense, żeby nie blokowały całej strony.

Typowe wpadki

  • QueryClient jako singleton w module na serwerze
  • staleTime 0 przy hydratacji i natychmiastowy refetch
  • Cache danych użytkownika w CDN

Dopytają o

  • Kiedy w ogóle potrzebujesz TanStack Query, mając Server Components?
  • Jak zrobisz invalidację po Server Action?
  • Jak wykryjesz wyciek danych między użytkownikami w testach?
Zapytaj Claude Rozwiń caseZagraj interviewera
Przypadek 4

Nieskończona lista z edycją, usuwaniem i sortowaniem

Lista zgłoszeń supportu ładuje się stronami po 50 (useInfiniteQuery). Użytkownik edytuje i usuwa zgłoszenia, a nowe zgłoszenia przychodzą na górę. Po edycji lista przeskakuje na początek albo dubluje elementy na granicy stron.

Zanim rozwiniesz: powiedz na głos, jak byś to rozwiązał, i nazwij co najmniej jeden kompromis.

Moje rozwiązanie

Zapisuje się samo w tej przeglądarce. Kopię zrobisz na stronie Notatki.

Pokaż, czego szuka rekruter, i modelową odpowiedź

Co sprawdza rekruter

  • Czy rozumiesz strukturę danych infinite query
  • Czy wiesz, jak aktualizować i invalidować wiele stron
  • Czy dobierasz paginację do zmieniających się danych

Odpowiedź seniora

Dane infinite query to pages i pageParams, więc edycję robię przez setQueryData, mapując wszystkie strony i podmieniając element po id. Usunięcie to filtrowanie ze strony, a nowe zgłoszenie dopisuję na początek pierwszej strony. Bez refetchu całej listy, bo invalidacja infinite query pobiera ponownie wszystkie załadowane strony po kolei.

Duble i przeskoki biorą się z paginacji offsetowej przy zmieniających się danych, więc zmieniam ją na kursor (id lub data ostatniego elementu, sortowanie stabilne z rozstrzygnięciem po id). Przy zmianie sortowania lub filtra to nowy klucz zapytania, a nie modyfikacja istniejącego.

Żeby zachować pozycję przewijania po powrocie, zostawiam dane w cache (gcTime) i przywracam scroll, a przy długiej sesji ograniczam liczbę stron w pamięci (maxPages). Lista jest zwirtualizowana.

Typowe wpadki

  • invalidateQueries po każdej edycji i pobranie 20 stron od nowa
  • Paginacja offsetowa przy danych dopisywanych na górę
  • Modyfikowanie obiektów stron w miejscu zamiast nowych referencji

Dopytają o

  • Jak zrobisz optimistic update usunięcia na liście stron?
  • Co jeśli edycja zmienia pozycję elementu w sortowaniu?
  • Jak zachowasz się, gdy element usunął ktoś inny?
Zapytaj Claude Rozwiń caseZagraj interviewera

Skróty klawiszowe

/
szukaj tematu
Enter
w wyszukiwarce: otwórz pierwszy wynik
N
notatki do tematu
[ ]
poprzedni / następny temat
G potem T
lista tematów
G potem P
powtórka
G potem N
wszystkie notatki
D
jasny / ciemny motyw
?
ta ściąga
Spacja, 1, 2, 3
w powtórce: pokaż, oceń

Pod każdym pytaniem są też skróty do Claude: rozwinięcie tematu, próbna rozmowa i ocena Twojej odpowiedzi z notatki.