nuqs@2.0.0 已可用,现在就试试吧:
npm install nuqs@latest它带来了令人兴奋的新功能和改进,包括:
- 支持其他 React 框架:Next.js、React SPA、Remix、React Router,以及更多即将到来
- 内置 测试适配器,用于隔离单元测试组件
- 捆绑大小改进
- 交互式文档,包含 社区解析器
你好,React! 👋 ⚛️
nuqs 最初是一个仅限 Next.js 的钩子,而 v2 带来了与其他 React 框架的兼容性:
- Next.js 14 & 15(app & pages 路由器)
- React SPA
- Remix
- React Router
使用 nuqs 钩子的组件无需更改代码, 使它们在所有支持的框架中实现 通用性。
唯一的新要求是将你的 React 树用相应框架的 适配器 包裹。
使用 Vite 的 React SPA 示例:
import { NuqsAdapter } from 'nuqs/adapters/react'
createRoot(document.getElementById('root')!).render(
<NuqsAdapter>
<App />
</NuqsAdapter>
)适配器文档 包含所有支持框架的示例。
测试
nuqs v1 的一个主要痛点是测试使用其钩子的组件。
Nuqs v2 带有内置 测试适配器,它模拟 URL 行为, 允许你在任何框架运行时之外隔离测试组件。
你可以使用任何渲染 React 组件的单元测试框架 (我推荐 Vitest & Testing Library)。
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. 通过传递初始搜索参数 / 查询字符串来设置测试:
wrapper: ({ children }) => (
<NuqsTestingAdapter searchParams="?count=42" onUrlUpdate={onUrlUpdate}>
{children}
</NuqsTestingAdapter>
)
})
// 2. 执行操作
const button = screen.getByRole('button')
await user.click(button)
// 3. 断言状态变化以及(模拟的)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')
})该适配器符合 setup / act / assert 测试策略,允许你:
- 设置初始 URL 搜索参数
- 让测试框架在组件上执行操作
- 断言 URL 作为结果而发生的变化
破坏性变更与迁移
最大的破坏性变更就是引入了 适配器。 另一个变更与已弃用的 API 相关。
开启这段旅程的 next-usequerystate 包不再更新。
所有更新现在都发布在 nuqs 包名下。
现在支持的最低 Next.js 版本是 14.2.0。它兼容
Next.js 15,包括服务器端缓存中的异步 searchParams 页面属性 (/docs/server-side)。
基于社区反馈,有一些重要的行为变更:
clearOnDefault现在默认为truestartTransition不再设置shallow: falseparseAsJson现在需要一个验证函数
阅读完整的 迁移指南 来更新你的 应用程序。
捆绑大小改进
通过转向 仅 ESM,并放弃支持旧版 Next.js 所需的黑客技巧, 捆绑大小现在比 v1 小 20%。它也是 无副作用的 且 可树摇 的。
未来计划?
社区和我对 nuqs 的未来有很多想法,包括:
- 在所有支持的 React 框架中提供统一、可扩展、类型安全的路由体验
- 社区贡献的解析器与适配器
- 新选项:防抖、全局默认值覆盖
- 用于将旧 URL 迁移到新 URL 的中间件
- 更好的 Zod 集成,用于类型安全与运行时安全的验证
致谢
我想感谢 赞助者、 贡献者 以及在 GitHub 和 X/Twitter 上提出问题和讨论的人。 你们是推动这个项目前进的不断增长的社区, 我对反馈感到非常高兴。
赞助者
- Pontus Abrahamsson,Midday.ai 的创始人
- Carl Lindesvard,OpenPanel 的创始人
- Robin Wieruch,The Road to Next 的作者
- Yoann Fleury
- Sunghyun Cho
- Jalol
感谢这些了不起的人,我能够投入更多时间到这个项目中,让它变得更好。 在 GitHub Sponsors 上加入他们!
贡献者
衷心感谢 @andreisocaciu、@tordans、@prasannamestha、@Talent30、@neefrehman、@chbg、@dopry、@weisisheng、@hugotiger、@iuriizaporozhets、@rikbrown、@mateogianolio、@timheerwagen、@psdmsft 和 @psdewar 的帮助!