# Loading data (https://docs.salla.dev/twilight/react/guide/loading-data)



Read this when a page needs store data such as products, categories or brands. The engine gives you two tools:
**loaders** that run before the page renders, and **API modules** that know how to talk to the store.

## What SSR means here [#what-ssr-means-here]

SSR (server-side rendering) means the server builds the page's HTML before the browser gets it.
Data fetched in a route loader is part of that HTML, so customers and search engines see content on the first paint,
with no spinner. Data fetched later in the browser is not.

<Callout>
  Default to a loader for anything the page needs to show. Use the browser only for things that change from user action,
  like the cart. See [Salla SDK and events](https://docs.salla.dev/twilight/react/guide/salla-sdk-and-events).
</Callout>

## A loader with an API module [#a-loader-with-an-api-module]

A loader returns the data the page component renders. It runs on the server for the first load,
and in the browser when the customer navigates inside the site. The engine's API modules are separate imports under
`@salla.sa/twilight-theme-engine/api/*`, so you only bundle what you use.

```tsx title="app/routes/our-brands.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { brand } from '@salla.sa/twilight-theme-engine/api/brands';

export const Route = createFileRoute('/{-$locale}/our-brands')({
  loader: () => brand.list(),
  component: OurBrands,
});

function OurBrands() {
  // brand.list() returns { items, next }: one page of brands and a cursor for the next page
  const { items } = Route.useLoaderData();
  return (
    <ul>
      {items.map((b) => (
        <li key={b.id}>
          <img src={b.logo} alt={b.name} width="200" height="150" />
        </li>
      ))}
    </ul>
  );
}
```

Add `route('/our-brands', 'our-brands.tsx')` to `app/routes.ts`, as shown in [Routes and pages](https://docs.salla.dev/twilight/react/guide/routes-and-pages).

Here is a real loader from the starter theme. It uses the page API and throws a 404 if the page is missing:

```tsx title="app/routes/page-single.tsx"
import { createFileRoute } from '@tanstack/react-router';
import { page as pageApi } from '@salla.sa/twilight-theme-engine/api/page';

export const Route = createFileRoute('/{-$locale}/$slug/page-{$id}')({
  loader: async ({ params }) => {
    const data = await pageApi.findOrThrow(params.id);
    return { page: { id: data.id, title: data.name, content: data.content } };
  },
  // …
});
```

## Reading API modules [#reading-api-modules]

Each module exports one object, such as `product`, `category`, `brand`, `page`, `cart`, `menu` or `store`.
Common names repeat across modules:

* `find(id)` reads one record. `list(...)` reads many.
* `findOrThrow(id)` does the same but throws, so a missing record becomes a 404 page. Prefer it in loaders.
  It exists on `product`, `category`, `brand`, `page`, `blog` and `order`.
* `queries` holds ready-made TanStack Query options for the same calls.

Method names are not identical everywhere (`cart.get` takes a cart id, `product.list` takes a `source`), so check the
[API tab](https://docs.salla.dev/twilight/react/api/modules) before you call one.

## Using the same data in a component [#using-the-same-data-in-a-component]

**TanStack Query** is the library that caches fetched data. The engine creates one query client for loaders and components,
so a component using `queries` shares the cache instead of fetching again. This real component from the starter theme
loads a product slider after the page has rendered:

```tsx title="app/components/home/ProductsSlider.tsx"
import { useQuery } from '@tanstack/react-query';
import { product, type ProductsListSource } from '@salla.sa/twilight-theme-engine/api/product';

function ProductsSlider({ source, sourceValue }: { source?: string; sourceValue?: number[] }) {
  const { data: result, isSuccess } = useQuery({
    ...product.queries.list({ source: source as ProductsListSource, sourceValue }),
    enabled: !!source,
  });
  if (!isSuccess) return null;
  return (
    <ul>
      {result.items.map((p) => (
        <li key={p.id}>{p.name}</li>
      ))}
    </ul>
  );
}
```

`useQuery` loads in the browser. Use `useSuspenseQuery` instead when the data should also be in the server HTML.

## Which one to use [#which-one-to-use]

| You need                                      | Use                                      |
| --------------------------------------------- | ---------------------------------------- |
| Data the page cannot render without           | Route `loader` + API module              |
| Extra data for one block, after paint         | `useQuery` with `module.queries`         |
| Data that changes on a click (cart, wishlist) | [Salla SDK](https://docs.salla.dev/twilight/react/guide/salla-sdk-and-events) |

**Next:** [Layout and components](https://docs.salla.dev/twilight/react/guide/layout-and-components), to change how pages look.
