generated from chiffre-io/template-library
-
-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
doc: v2 announcement blog post (#687)
* doc: Add blog engine from Fumadocs * doc: Add v2 announcement banners * doc: Make blog posts look pretty * doc: Blog post contents * doc: Add og:images * doc: Add blog post og:image * doc: Wording fixes * doc: Add v2 blog link to playground
- Loading branch information
Showing
36 changed files
with
404 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
--- | ||
title: nuqs 2 | ||
description: Opening up to other React frameworks | ||
author: François Best | ||
date: 2024-10-22 | ||
--- | ||
|
||
[email protected] is available, try it now: | ||
|
||
```bash | ||
pnpm add nuqs@latest | ||
``` | ||
|
||
It's packing exciting features & improvements, including: | ||
|
||
- [Support for other React frameworks](#hello-react): Next.js, React SPA, Remix, React Router, and more to come | ||
- A built-in [testing adapter](#testing) to unit-test your components in isolation | ||
- [Bundle size improvements](#bundle-size-improvements) | ||
- Interactive documentation, with [community parsers](/docs/parsers/community) | ||
|
||
<hr/> | ||
|
||
## Hello, React! 👋 ⚛️ [#hello-react] | ||
|
||
nuqs started as a Next.js-only hook, and v2 brings compatibility for other React frameworks: | ||
|
||
- Next.js 14 & 15 (app & pages routers) | ||
- React SPA | ||
- Remix | ||
- React Router | ||
|
||
No code change is necessary in components that use nuqs hooks, | ||
making them **universal** across all supported frameworks. | ||
|
||
The only new requirement is to wrap your React tree with an | ||
[adapter](/docs/adapters) for your framework. | ||
|
||
Example for a React SPA with Vite: | ||
|
||
```tsx title="src/main.tsx" | ||
// [!code word:NuqsAdapter] | ||
import { NuqsAdapter } from 'nuqs/adapters/react' | ||
|
||
createRoot(document.getElementById('root')!).render( | ||
<NuqsAdapter> | ||
<App /> | ||
</NuqsAdapter> | ||
) | ||
``` | ||
|
||
<Callout> | ||
The [adapters documentation](/docs/adapters) has examples for all supported frameworks. | ||
</Callout> | ||
|
||
## Testing | ||
|
||
One of the major pain points with nuqs v1 was testing components that used its hooks. | ||
|
||
Nuqs v2 comes with a built-in [testing adapter](/docs/testing) that mocks URL behaviours, | ||
allowing you to test your components in isolation, outside of any framework runtime. | ||
|
||
You can use it with any unit testing framework that renders React components | ||
(I recommend [Vitest](https://vitest.dev) & [Testing Library](https://testing-library.com/)). | ||
|
||
```tsx title="counter-button.test.tsx" | ||
// [!code word:NuqsTestingAdapter] | ||
import { render, screen } from '@testing-library/react' | ||
import userEvent from '@testing-library/user-event' | ||
import { NuqsTestingAdapter, type UrlUpdateEvent } from 'nuqs/adapters/testing' | ||
import { describe, expect, it, vi } from 'vitest' | ||
import { CounterButton } from './counter-button' | ||
|
||
it('should increment the count when clicked', async () => { | ||
const user = userEvent.setup() | ||
const onUrlUpdate = vi.fn<[UrlUpdateEvent]>() | ||
render(<CounterButton />, { | ||
// 1. Setup the test by passing initial search params / querystring: | ||
wrapper: ({ children }) => ( | ||
<NuqsTestingAdapter searchParams="?count=42" onUrlUpdate={onUrlUpdate}> | ||
{children} | ||
</NuqsTestingAdapter> | ||
) | ||
}) | ||
// 2. Act | ||
const button = screen.getByRole('button') | ||
await user.click(button) | ||
// 3. Assert changes in the state and in the (mocked) URL | ||
expect(button).toHaveTextContent('count is 43') | ||
expect(onUrlUpdate).toHaveBeenCalledOnce() | ||
expect(onUrlUpdate.mock.calls[0][0].queryString).toBe('?count=43') | ||
expect(onUrlUpdate.mock.calls[0][0].searchParams.get('count')).toBe('43') | ||
expect(onUrlUpdate.mock.calls[0][0].options.history).toBe('push') | ||
}) | ||
``` | ||
|
||
The adapter conforms to the **setup** / **act** / **assert** testing strategy, allowing you | ||
to: | ||
|
||
1. Set the initial URL search params | ||
2. Let your test framework perform actions on your component | ||
3. Asserting on how the URL was changed as a result | ||
|
||
## Breaking changes & migration | ||
|
||
The biggest breaking change is the introduction of [adapters](/docs/adapters). | ||
Another one is related to deprecated APIs. | ||
|
||
The `next-usequerystate` package that started this journey is no longer updated. | ||
All updates are now published under the `nuqs` package name. | ||
|
||
The minimum version of Next.js supported is now 14.2.0. It is compatible with | ||
Next.js 15, including the async `searchParams{:ts}` page prop in the [server-side cache](/docs/server-side). | ||
|
||
There are some important behaviour changes, based on feedback from the community: | ||
|
||
- [`clearOnDefault{:ts}`](/docs/options#clear-on-default) is now `true{:ts}` by default | ||
- [`startTransition{:ts}`](/docs/options#transitions) no longer sets `shallow: false{:ts}` | ||
- [`parseAsJson{:ts}`](/docs/parsers/built-in#json) now requires a validation function | ||
|
||
<Callout> | ||
Read the complete [migration guide](/docs/migrations/v2) to update your applications. | ||
</Callout> | ||
|
||
## Bundle size improvements | ||
|
||
By moving to **ESM-only**, and dropping hacks needed to support older versions of Next.js, | ||
the bundle size is now **20% smaller** than v1. It's also **side-effects free** and **tree-shakable**. | ||
|
||
## What's next? | ||
|
||
The community and I have a lot of ideas for the future of nuqs, including: | ||
|
||
- A unified, scalable, type-safe routing experience in all supported React frameworks | ||
- Community-contributed parsers & adapters | ||
- New options: debouncing, global defaults override | ||
- Middleware to migrate old URLs to new ones | ||
- Better Zod integration for type-safe & runtime-safe validation | ||
|
||
## Thanks | ||
|
||
I want to thank [sponsors](https://github.com/sponsors/franky47), | ||
[contributors](https://github.com/47ng/nuqs/graphs/contributors) | ||
and people who raised issues and discussions on | ||
[GitHub](https://github.com/47ng/nuqs) and [X/Twitter](https://x.com/nuqs47ng). | ||
You are the growing community that drives this project forward, | ||
and I couldn't be happier with the response. | ||
|
||
### Sponsors | ||
|
||
- [Pontus Abrahamsson](https://x.com/pontusab), founder of [Midday.ai](https://midday.ai) | ||
- [Carl Lindesvard](https://x.com/CarlLindesvard), founder of [OpenPanel](https://openpanel.dev) | ||
- [Robin Wieruch](https://x.com/rwieruch), author of [The Road to Next](https://www.road-to-next.com/) | ||
- [Yoann Fleury](https://x.com/YoannFleuryDev) | ||
- [Sunghyun Cho](https://github.com/anaclumos) | ||
- [Jalol](https://github.com/mirislomovmirjalol) | ||
|
||
Thanks to these amazing people, I'm able to dedicate more time to this project and make it better for everyone. | ||
Join them on [GitHub Sponsors](https://github.com/sponsors/franky47)! | ||
|
||
### Contributors | ||
|
||
Huge thanks to [@andreisocaciu](https://github.com/andreisocaciu), [@tordans](https://github.com/tordans), [@prasannamestha](https://github.com/prasannamestha), [@Talent30](https://github.com/Talent30), [@neefrehman](https://github.com/neefrehman), [@chbg](https://github.com/chbg), [@dopry](https://github.com/dopry), [@weisisheng](https://github.com/weisisheng), [@hugotiger](https://github.com/hugotiger), [@iuriizaporozhets](https://github.com/iuriizaporozhets), [@rikbrown](https://github.com/rikbrown), [@mateogianolio](https://github.com/mateogianolio), [@timheerwagen](https://github.com/timheerwagen), [@psdmsft](https://github.com/psdmsft), and [@psdewar](https://github.com/psdewar) for helping! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,7 +81,7 @@ export default function MyApp({ Component, pageProps }: AppProps) { | |
#### Unified (router-agnostic) | ||
|
||
If your Next.js app uses **both the app and pages routers** and the adapter needs | ||
to be mounted in either, you can use the unified adapter, at the cost | ||
to be mounted in either, you can import the unified adapter, at the cost | ||
of a slightly larger bundle size (~100B). | ||
|
||
```tsx | ||
|
@@ -93,8 +93,6 @@ import { NuqsAdapter } from 'nuqs/adapters/next' | |
Albeit not part of a migration from v1, you can now use nuqs in other React | ||
frameworks via their respective [adapters](/docs/adapters). | ||
|
||
{/* todo: Add the docs/adapters page */} | ||
|
||
However, there's one more adapter that might be of interest to you, and solves | ||
a long-standing issue with testing components using nuqs hooks: | ||
|
||
|
@@ -188,7 +186,7 @@ const { useQueryState } = await import('nuqs') | |
Some of the v1 API was marked as deprecated back in September 2023, and has been | ||
removed in `[email protected]`. | ||
|
||
### `queryTypes{:ts}` parsers object | ||
### `queryTypes` parsers object | ||
|
||
The `queryTypes{:ts}` object has been removed in favor of individual parser exports, | ||
for better tree-shaking. | ||
|
@@ -205,7 +203,7 @@ Replace with `parseAsXYZ{:ts}` to match: | |
+ useQueryState('page', parseAsInteger.withDefault(1)) | ||
``` | ||
|
||
### `subscribeToQueryUpdates{:ts}` | ||
### `subscribeToQueryUpdates` | ||
|
||
Next.js 14.1.0 makes `useSearchParams{:ts}` reactive to shallow search params updates, | ||
which makes this internal helper function redundant. See [#425](https://github.com/47ng/nuqs/pull/425) for context. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.