# Navigation and page detection (https://docs.salla.dev/twilight/react/hooks/navigation)



Use these when a component needs to **go somewhere**, to **know which page it is on**, or when a loader needs to **send the customer away** or show a 404. For a plain link in markup, use [`Link`](https://docs.salla.dev/twilight/react/components/link).

All of them come from `@salla.sa/twilight-theme-engine/providers`.

## Example [#example]

```tsx title="app/components/layout/CartShortcut.tsx"
import { useIsCart, useLocation, useNavigate } from '@salla.sa/twilight-theme-engine/providers';

export function CartShortcut() {
  const navigate = useNavigate();
  const isCart = useIsCart();
  const { pathname, search } = useLocation<{ q?: string }>();

  if (isCart) return null;
  return (
    <button onClick={() => navigate('/cart')} data-from={pathname} data-query={search.q}>
      Go to cart
    </button>
  );
}
```

## In components [#in-components]

| Hook                     | Returns                                              | Notes                                                                                                             |
| ------------------------ | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `useNavigate()`          | `(to: string, opts?: { replace?: boolean }) => void` | Navigates in the browser without a page reload. `replace: true` replaces the history entry instead of adding one. |
| `useRouteId()`           | `string`                                             | The id of the current route, such as `'product.single'`. Compare it with the `RouteId` constants.                 |
| `useLocation<TSearch>()` | `Location`                                           | Current URL. Works during server rendering, unlike `window.location`.                                             |

`Location` has these fields:

| Field       | Type                      | Description                                 |
| ----------- | ------------------------- | ------------------------------------------- |
| `pathname`  | `string`                  | Path, such as `/ar/products`.               |
| `search`    | `TSearch`                 | Query string already parsed into an object. |
| `searchStr` | `string`                  | Query string as text, such as `?q=shoes`.   |
| `hash`      | `string`                  | The part after `#`.                         |
| `href`      | `string`                  | The full address.                           |
| `state`     | `Record<string, unknown>` | History state.                              |

### Page checks [#page-checks]

Each returns `true` on the matching page, and re-renders when the page changes.

| Hook              | True on                                              |
| ----------------- | ---------------------------------------------------- |
| `useIsHome()`     | The home page                                        |
| `useIsProduct()`  | A product page (the detail page, not a product list) |
| `useIsCart()`     | The cart                                             |
| `useIsCustomer()` | Any customer account page                            |
| `useIsBlog()`     | The blog list and a blog article                     |
| `useIsBrands()`   | The brands list and a brand page                     |
| `useIsSearch()`   | Search results                                       |

For any other page, compare `useRouteId()` with a constant:

```tsx
import { RouteId, useRouteId } from '@salla.sa/twilight-theme-engine/providers';

const isWishlist = useRouteId() === RouteId.CUSTOMER_WISHLIST;
```

## In loaders [#in-loaders]

A loader runs before the page renders, outside React, so it cannot use hooks. Throw one of these instead. Each never returns.

```ts title="app/routes/my-page.tsx"
import { notFound, orThrow, redirect, unauthorized } from '@salla.sa/twilight-theme-engine/providers';

if (!user) throw unauthorized();
if (moved) throw redirect('/ar/new-path', { statusCode: 301 });
const product = await orThrow(api.find(id)); // a 404 or 410 becomes notFound()
```

| Function                                    | Result                                                                                                 |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `notFound(message?)`                        | The not-found page.                                                                                    |
| `unauthorized(message?)`                    | Sends a signed-out customer to the login page, and back to this page after signing in.                 |
| `redirect(path, { replace?, statusCode? })` | A redirect. `statusCode` defaults to `307`; use `301` for a URL that moved for good.                   |
| `orThrow(promise)`                          | Awaits the promise. On a `404` or `410` response it calls `notFound()`; other errors pass through.     |
| `orUnauthorized(promise)`                   | Awaits the promise. On a `401` or `403` response it calls `unauthorized()`; other errors pass through. |

## Gotchas [#gotchas]

* Navigate with `useNavigate` or `Link`, never `window.location`. Assigning `window.location` reloads the whole page, and reading it breaks on the server.
* `useLocation().search` is an object, not text. Use `searchStr` when you need the raw `?a=b`.
* Route ids are strings like `product.single`, not URL paths. Use `RouteId` rather than typing them.
* A product list is not a product page. A category and every [`/products?source=…`](https://docs.salla.dev/twilight/react/routes/products) list are `RouteId.PRODUCT_INDEX` (`product.index`); search results are `RouteId.SEARCH`. The old `PRODUCT_INDEX_LATEST`, `PRODUCT_INDEX_SALES` and `PRODUCT_INDEX_OFFERS` ids are only the `page.slug` of those lists now, so tell them apart with `page.slug` or `source.type`.

## Next [#next]

* [`Link`](https://docs.salla.dev/twilight/react/components/link): the markup version of navigation.
* [Loading data](https://docs.salla.dev/twilight/react/guide/loading-data) and [Routes and pages](https://docs.salla.dev/twilight/react/guide/routes-and-pages) show loaders in context.
* [Salla SDK and events](https://docs.salla.dev/twilight/react/guide/salla-sdk-and-events): the `route::changed` event for reacting to navigation.
