Przejdź do głównej zawartości

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.

SDK jest agnostyczne

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:

OpcjaZnaczenie
variablesZmienne operacji. Zmiana wartości przeładowuje (reset + nowy odczyt).
enabledGdy false, żądanie nie startuje (stan pozostaje „pending"). Domyślnie true.
cacheStrategia cache przekazywana do client.query (istotna tylko dla katalogu — wpływa na cache na brzegu sieci).
clientKlient, z którego czytamy. Domyślnie najbliższy klient publiczny.
resetKeyDodatkowa 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

PoleZnaczenie
dataWynik dla bieżących wejść, albo undefined gdy trwa ładowanie / wystąpił błąd.
errorObiekt StorefrontError albo null.
isPendingtrue, 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.
isFetchingtrue, gdy żądanie jest w locie (pierwszy odczyt lub refetch).
isLoadingtrue, 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 / isSuccessStan 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.

Izolacja kont na wspólnym urządzeniu

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