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​