Skip to content

Commit 5683d48

Browse files
committedDec 26, 2024
doc: Add loaders docs
1 parent fc5041d commit 5683d48

File tree

1 file changed

+122
-7
lines changed

1 file changed

+122
-7
lines changed
 

Diff for: ‎packages/docs/content/docs/server-side.mdx

+122-7
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,126 @@ title: Server-Side usage
33
description: Type-safe search params on the server
44
---
55

6+
## Loaders
7+
8+
To parse search params server-side, you can use a _loader_ function.
9+
10+
You create one using the `createLoader` function, by passing it your search params
11+
descriptor object:
12+
13+
```tsx title="searchParams.tsx"
14+
// [!code word:createLoader]
15+
import { parseAsFloat, createLoader } from 'nuqs/server'
16+
17+
// Describe your search params, and reuse this in useQueryStates / createSerializer:
18+
export const coordinatesSearchParams = {
19+
latitude: parseAsFloat.withDefault(0)
20+
longitude: parseAsFloat.withDefault(0)
21+
}
22+
23+
export const loadSearchParams = createLoader(coordinatesSearchParams)
24+
```
25+
26+
Here, `loadSearchParams{:ts}` is a function that parses search params and returns
27+
state variables to be consumed server-side (the same state type that `useQueryStates{:ts}` returns).
28+
29+
<Tabs items={["Next.js (app router)", "Next.js (pages router)", "API routes", "Remix / React Router", "React / client-side"]}>
30+
31+
```tsx tab="Next.js (app router)" title="app/page.tsx"
32+
// [!code word:loadSearchParams]
33+
import { loadSearchParams } from './search-params'
34+
import type { SearchParams } from 'nuqs/server'
35+
36+
type PageProps = {
37+
searchParams: Promise<SearchParams>
38+
}
39+
40+
export default async function Page({ searchParams }: PageProps) {
41+
const { latitude, longitude } = await loadSearchParams(searchParams)
42+
return <Map
43+
lat={latitude}
44+
lng={longitude}
45+
/>
46+
47+
// Pro tip: you don't *have* to await the result.
48+
// pass the Promise object to children components wrapped in Suspense
49+
// to benefit from PPR / dynamicIO and serve a static outer shell
50+
// immediately, while streaming in the dynamic parts that depend on
51+
// the search params when they become available.
52+
}
53+
```
54+
55+
```ts tab="Next.js (pages router)" title="pages/index.tsx"
56+
// [!code word:loadSearchParams]
57+
import type { GetServerSidePropsContext } from 'next'
58+
59+
export async function getServerSideProps({ query }: GetServerSidePropsContext) {
60+
const { latitude, longitude } = loadSearchParams(query)
61+
// Do some server-side calculations with the coordinates
62+
return {
63+
props: { ... }
64+
}
65+
}
66+
```
67+
68+
```tsx tab="Remix / React Router" title="app/routes/_index.tsx"
69+
// [!code word:loadSearchParams]
70+
export function loader({ request }: LoaderFunctionArgs) {
71+
const { latitude, longitude } = loadSearchParams(request) // request.url works too
72+
// Do some server-side calculations with the coordinates
73+
return ...
74+
}
75+
```
76+
77+
```tsx tab="React / client-side"
78+
// Note: you can also use this client-side (or anywhere, really),
79+
// for a one-off parsing of non-reactive search params:
80+
81+
loadSearchParams('https://example.com?latitude=42&longitude=12')
82+
loadSearchParams(location.search)
83+
loadSearchParams(new URL(...))
84+
loadSearchParams(new URLSearchParams(...))
85+
```
86+
87+
```tsx tab="API routes"
88+
// App router, eg: app/api/location/route.ts
89+
export async function GET(request: Request) {
90+
const { latitude, longitude } = loadSearchParams(request)
91+
// ...
92+
}
93+
94+
// Pages router, eg: pages/api/location.ts
95+
import type { NextApiRequest, NextApiResponse } from 'next'
96+
export default function handler(
97+
request: NextApiRequest,
98+
response: NextApiResponse
99+
) {
100+
const { latitude, longitude } = loadSearchParams(request.query)
101+
}
102+
```
103+
104+
</Tabs>
105+
106+
<Callout type="warn" title="Note">
107+
Loaders **don't validate** your data. If you expect positive integers
108+
or JSON-encoded objects of a particular shape, you'll need to feed the result
109+
of the loader to a schema validation library, like [Zod](https://zod.dev).
110+
111+
Built-in validation support is coming. [Read the RFC](https://github.com/47ng/nuqs/discussions/446).
112+
Alternatively, you can build validation into [custom parsers](/docs/parsers/making-your-own).
113+
</Callout>
114+
115+
116+
- A string containing a fully qualified URL (eg: `https://example.com/?foo=bar`)
117+
- A string containing just search params (like `location.search`, eg: `?foo=bar`)
118+
- A `URL{:ts}` object
119+
- A `URLSearchParams{:ts}` object
120+
- A `Request{:ts}` object
121+
- A `Record<string, string | string[] | undefined>{:ts}` (eg: `{ foo: 'bar' }{:ts}`)
122+
- A `Promise{:ts}` of any of the above, in which case it also returns a Promise.
123+
124+
## Cache
125+
6126
<Callout>
7127
This feature is available for Next.js only.
8128
</Callout>
@@ -11,13 +131,8 @@ If you wish to access the searchParams in a deeply nested Server Component
11131
(ie: not in the Page component), you can use `createSearchParamsCache{:ts}`
12132
to do so in a type-safe manner.
13133

14-
<Callout type="warn" title="Note">
15-
Parsers **don't validate** your data. If you expect positive integers
16-
or JSON-encoded objects of a particular shape, you'll need to feed the result
17-
of the parser to a schema validation library, like [Zod](https://zod.dev).
18-
19-
Built-in validation support is coming. [Read the RFC](https://github.com/47ng/nuqs/discussions/446)
20-
</Callout>
134+
Think of it as a loader combined with a way to propagate the parsed values down
135+
the RSC tree, like Context would on the client.
21136

22137
```ts title="searchParams.ts"
23138
import {

0 commit comments

Comments
 (0)
Failed to load comments.