Skip to content

Commit 863f789

Browse files
committed
doc: Add adapters in v2 migration docs
1 parent ba555b5 commit 863f789

File tree

1 file changed

+135
-1
lines changed
  • packages/docs/content/docs/migrations

1 file changed

+135
-1
lines changed

Diff for: packages/docs/content/docs/migrations/v2.mdx

+135-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,147 @@ title: Migration guide to v2
33
description: How to update your code to use nuqs@2.0.0
44
---
55

6-
## Support moved to `next@>=14.1.2`
6+
Here's a summary of the breaking changes in `nuqs@2.0.0`:
7+
8+
- [Enable support for other React frameworks](#adapters)
9+
- [ESM-only package](#esm-only)
10+
- [Deprecated exports have been removed](#deprecated-exports)
11+
- [Renamed `nuqs/parsers` to `nuqs/server`](#renamed-nuqs-parsers-to-nuqs-server)
12+
- [Debug printout detection](#debug-printout-detection)
13+
14+
## Adapters
15+
16+
The biggest change is that `nuqs@2.0.0` now supports other React frameworks,
17+
providing type-safe URL state for all.
18+
19+
You will need to wrap your app with the appropriate **adapter** for your framework,
20+
to let the hooks know how to interact with its router.
21+
22+
Adapters are currently available for:
23+
- Next.js (app & pages routers)
24+
- React (Vite, Astro, etc.)
25+
- Testing environments (Vitest, Jest, etc.)
26+
27+
More adapters will be released soon (React Router, Remix etc.), PRs are welcome!
28+
29+
### Next.js
30+
31+
<Callout title="Minimum required version: next@>=14.1.2">
732

833
Early versions of Next.js 14 were in flux with regards to shallow routing,
934
only from 14.1.2 is it stable enough to not require ugly hacks.
1035

1136
See #423 for context and a table of supported versions.
1237

38+
</Callout>
39+
40+
#### App router
41+
42+
```tsx
43+
// src/app/layout.tsx
44+
import { NuqsAdapter } from 'nuqs/adapters/next/app'
45+
import { type ReactNode } from 'react'
46+
47+
export default function RootLayout({
48+
children
49+
}: {
50+
children: ReactNode
51+
}) {
52+
return (
53+
<html>
54+
<body>
55+
<NuqsAdapter>{children}</NuqsAdapter>
56+
</body>
57+
</html>
58+
)
59+
}
60+
```
61+
62+
#### Pages router
63+
64+
```tsx
65+
// src/pages/_app.tsx
66+
import type { AppProps } from 'next/app'
67+
import { NuqsAdapter } from 'nuqs/adapters/next/pages'
68+
69+
export default function MyApp({ Component, pageProps }: AppProps) {
70+
return (
71+
<NuqsAdapter>
72+
<Component {...pageProps} />
73+
</NuqsAdapter>
74+
)
75+
}
76+
```
77+
78+
<details>
79+
<summary>
80+
81+
#### Next.js (unified)
82+
83+
</summary>
84+
85+
If your Next.js app uses both the app _and_ pages routers, you can use
86+
the unified adapter if it needs to be mounted in either routers, at the cost
87+
of a slightly larger bundle size (~100B).
88+
89+
```tsx
90+
import { NuqsAdapter } from 'nuqs/adapters/next'
91+
```
92+
93+
</details>
94+
95+
### React (with Vite)
96+
97+
```tsx
98+
import { NuqsAdapter } from 'nuqs/adapters/react'
99+
100+
createRoot(document.getElementById('root')!).render(
101+
<NuqsAdapter>
102+
<App />
103+
</NuqsAdapter>
104+
)
105+
```
106+
107+
### Testing adapter
108+
109+
Until now, unit-testing nuqs components was a hassle, as it required mocking
110+
Next.js internals, causing abstraction leaks.
111+
112+
You can now wrap your components to test with the `NuqsTestingAdapter`, which
113+
provides setup & assertion helpers for your tests.
114+
115+
Here's an example with Vitest & Testing Library:
116+
117+
```tsx
118+
import { render, screen } from '@testing-library/react'
119+
import userEvent from '@testing-library/user-event'
120+
import { NuqsTestingAdapter, type UrlUpdateEvent } from 'nuqs/adapters/testing'
121+
import { describe, expect, it, vi } from 'vitest'
122+
import { CounterButton } from './counter-button'
123+
124+
it('should increment the count when clicked', async () => {
125+
const user = userEvent.setup()
126+
const onUrlUpdate = vi.fn<[UrlUpdateEvent]>()
127+
render(<CounterButton />, {
128+
// Setup the test by passing initial search params / querystring:
129+
wrapper: ({ children }) => (
130+
<NuqsTestingAdapter searchParams="?count=1" onUrlUpdate={onUrlUpdate}>
131+
{children}
132+
</NuqsTestingAdapter>
133+
)
134+
})
135+
// Act
136+
const button = screen.getByRole('button')
137+
await user.click(button)
138+
// Assert changes in the state and in the (mocked) URL
139+
expect(button).toHaveTextContent('count is 2')
140+
expect(onUrlUpdate).toHaveBeenCalledOnce()
141+
expect(onUrlUpdate.mock.calls[0][0].queryString).toBe('?count=2')
142+
expect(onUrlUpdate.mock.calls[0][0].searchParams.get('count')).toBe('2')
143+
expect(onUrlUpdate.mock.calls[0][0].options.history).toBe('push')
144+
})
145+
```
146+
13147
## ESM only
14148

15149
`nuqs@2.0.0` is now an [ESM-only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c)

0 commit comments

Comments
 (0)