Pobieranie danych po stronie klienta
Katalog (produkty, kategorie) pobierasz najczęściej na serwerze — w Server Component, gdzie dane wchodzą jako props i strona zostaje statyczna/cacheowalna na brzegu sieci (edge). Tam hook kliencki jest zbędny.
Inaczej jest z kontem klienta (profil, zamówienia, adresy, program lojalnościowy) oraz z interaktywnymi odczytami katalogu (podpowiedzi wyszukiwarki, „pokaż więcej", filtrowanie po stronie klienta). To są odczyty w przeglądarce, w Client Components — i właśnie dla nich SDK daje dwa hooki.
client.query to zwykła, typowana funkcja zwracająca Promise. Możesz jej użyć z naszym
hookiem, ale równie dobrze jako queryFn w TanStack Query, fetcher w SWR, albo w surowym
useEffect. SDK nie narzuca żadnej biblioteki — wybór mechanizmu (i tego, czy chcesz cache
w przeglądarce) należy do Ciebie.
useStorefrontQuery — odczyt katalogu
Zero-config hook z gotową maszyną stanów: data, error, flagi ładowania, brama enabled,
refetch, anulowanie żądania i ponowne kluczowanie (przy zmianie wejść nigdy nie pokaże wyniku
dla poprzednich).
'use client';
import { useStorefrontQuery } from '@doswiftly/storefront-sdk/react';
import { SearchProductsQuery } from '@/graphql/catalog';
function SearchBox({ query }: { query: string }) {
const { data, isFetching, isError } = useStorefrontQuery(SearchProductsQuery, {
variables: { query },
enabled: query.length > 1, // nie odpytuj dla pustego/jednoznakowego zapytania
});
if (isError) return <p>Nie udało się wczytać podpowiedzi.</p>;
return <ResultsList items={data?.searchProducts.nodes ?? []} busy={isFetching} />;
}
Opcje:
| Opcja | Znaczenie |
|---|---|
variables | Zmienne operacji. Zmiana wartości przeładowuje (reset + nowy odczyt). |
enabled | Gdy false, żądanie nie startuje (stan pozostaje „pending"). Domyślnie true. |
cache | Strategia cache przekazywana do client.query (istotna tylko dla katalogu — wpływa na cache na brzegu sieci). |
client | Klient, z którego czytamy. Domyślnie najbliższy klient publiczny. |
resetKey | Dodatkowa oś klucza. Zmiana resetuje dane i przeładowuje. |
useCustomerQuery — odczyt konta klienta
Specjalizacja useStorefrontQuery dla powierzchni konta klienta. Dokłada dwie rzeczy, których
odczyt konta zawsze potrzebuje:
- czeka na gotowość sesji — pierwszy odczyt po twardym odświeżeniu nie wystartuje, zanim sesja się ustali (inaczej zalogowany kupujący na moment wyglądałby jak wylogowany);
- kluczuje po zalogowanym kliencie — po zmianie konta (wyloguj/zaloguj) dane poprzedniego konta nigdy nie zostają na ekranie.
'use client';
import { useCustomerQuery } from '@doswiftly/storefront-sdk/react';
import { RecentOrdersQuery } from '@/graphql/account';
function RecentOrders() {
const { data, isLoading, error } = useCustomerQuery(RecentOrdersQuery, {
variables: { first: 5 },
});
// `isLoading` (nie `isPending`) — dla gościa zapytanie jest wstrzymane, więc `isLoading` jest
// `false` i renderujesz stan pusty zamiast wiecznego spinnera.
if (isLoading) return <Spinner />;
if (error) return <p>{error.message}</p>;
return <OrdersList orders={data?.customer?.orders.nodes ?? []} />;
}
useCustomerQuery przyjmuje tylko variables i enabled (łączony bramką sesji — żądanie rusza,
gdy oba są spełnione). Powierzchnia konta jest zawsze świeża, więc nie ma tu opcji cache.
Co zwracają oba hooki
| Pole | Znaczenie |
|---|---|
data | Wynik dla bieżących wejść, albo undefined gdy trwa ładowanie / wystąpił błąd. |
error | Obiekt StorefrontError albo null. |
isPending | true, dopóki bieżące wejścia nie rozstrzygną się po raz pierwszy — w tym gdy zapytanie jest wstrzymane (enabled: false). Do spinnera użyj isLoading, nie tego pola. |
isFetching | true, gdy żądanie jest w locie (pierwszy odczyt lub refetch). |
isLoading | true, gdy żądanie jest w locie i nie ma jeszcze danych (isPending && isFetching) — właściwa brama dla spinnera pierwszego ładowania. false, gdy zapytanie jest wstrzymane, więc gość na widoku konta nie zobaczy wiecznego spinnera. |
isError / isSuccess | Stan końcowy dla bieżących wejść. |
refetch() | Ponawia odczyt dla bieżących wejść. Stabilna referencja (też przez adapter biblioteki). |
Granica: bez cache między komponentami
Te hooki trzymają stan per komponent. Świadomie nie mają: współdzielonego cache między komponentami, ponownego odczytu przy powrocie do karty przeglądarki, ani narzędzi developerskich. Dwa komponenty z tym samym odczytem konta wykonają dwa żądania.
Jeśli tego potrzebujesz — przejdź do następnej sekcji.
Cache w przeglądarce — zarejestruj bibliotekę server-state
Dane konta (zamówienia, profil) nie są cacheowane na brzegu sieci, więc to cache w przeglądarce
sprawia, że wracający użytkownik nie pobiera ich ponownie. Zarejestruj swoją bibliotekę raz na
<StorefrontProvider queryAdapter={…}>. Hooki danych czytają wtedy przez nią — kluczowane po
koncie, bramkowane na sesję i czyszczone przy wylogowaniu / wygaśnięciu sesji automatycznie:
// app/providers.tsx
'use client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { StorefrontProvider } from '@doswiftly/storefront-sdk/react';
import { createTanstackQueryAdapter } from '@doswiftly/storefront-sdk/react/tanstack';
const queryClient = new QueryClient();
export function Providers({ children, shopData }) {
return (
<QueryClientProvider client={queryClient}>
<StorefrontProvider shopData={shopData} queryAdapter={createTanstackQueryAdapter(queryClient)}>
{children}
</StorefrontProvider>
</QueryClientProvider>
);
}
// TEN SAM hook — teraz cache między komponentami, kluczowany po koncie, czyszczony na wylogowaniu.
const { data, isPending } = useCustomerQuery(RecentOrdersQuery, { variables: { first: 20 } });
@tanstack/react-query to opcjonalna zależność peer (instaluj tylko, jeśli używasz tego adaptera).
Do zaawansowanych funkcji biblioteki, których adapter nie udostępnia (select, infinite,
optimistic, …), użyj biblioteki bezpośrednio z useCustomerClient() + client.query. Inną
bibliotekę (SWR, urql) podłączysz, implementując port StorefrontQueryAdapter samodzielnie.
Bezpieczny cache per użytkownik stoi na trzech filarach: klucz zawiera identyfikator
zalogowanego klienta, brama enabled czeka na sesję, a clear() usuwa cache przy
wylogowaniu i wygaśnięciu sesji. Rejestrując adapter na providerze, dostajesz wszystkie trzy od
SDK. Jeśli zamiast tego podłączasz bibliotekę ręcznie — zadbaj o każdy z nich sam.
Powiązane
- Konto klienta — operacje na profilu i adresach.
- Zamówienia — historia zamówień i odczyt po tokenie gościa.
- Autoryzacja klienta — logowanie, rejestracja, sesja.