47ng / nuqs

Type-safe search params state manager for React frameworks - Like useState, but stored in the URL query string.
https://nuqs.47ng.com
MIT License
4.73k stars 103 forks source link

feat: Introducing adapters for other frameworks #644

Closed franky47 closed 3 weeks ago

franky47 commented 1 month ago

Tasks

~idea: Should the React adapter provide initial search params on the server for custom SSR implementations?~ -> Not on this version, can be an improvement later. Resources: Vite + React SSR

~Add docs on how to create adapters (for external contributions)~ -> can be done in a later time as it's all experimental

Breaking changes

nuqs now requires wrapping your app with a NuqsAdapter (see below), which is a context provider connecting your framework APIs to the hooks' internals.

The startTransition option no longer automatically sets shallow: false.

The Options type is no longer generic.

The "use client" directive was not included in the client import (import {} from 'nuqs'). It has now been added, meaning that server-side code needs to import from nuqs/server to avoid errors like:

Error: Attempted to call withDefault() from the server but withDefault is on
the client. It's not possible to invoke a client function from the server, it can
only be rendered as a Component or passed to props of a Client
Component.

Adapters

You'll need to wrap your application in a NuqsAdapter, as such:

Next.js, app router:

// src/app/layout.tsx
import { NuqsAdapter } from 'nuqs/adapters/next/app'
import { type ReactNode } from 'react'

export default function RootLayout({
  children
}: {
  children: ReactNode
}) {
  return (
    <html>
      <body>
        <NuqsAdapter>{children}</NuqsAdapter>
      </body>
    </html>
  )
}

Next.js, pages router:

// src/pages/_app.tsx
import type { AppProps } from 'next/app'
import { NuqsAdapter } from 'nuqs/adapters/next/pages'

export default function MyApp({ Component, pageProps }: AppProps) {
  return (
    <NuqsAdapter>
      <Component {...pageProps} />
    </NuqsAdapter>
  )
}

The main reason for adapters is to open up nuqs to other React frameworks:

Vanilla React (eg: with Vite):

import { NuqsAdapter } from 'nuqs/adapters/react'

createRoot(document.getElementById('root')!).render(
  <NuqsAdapter>
    <App />
  </NuqsAdapter>
)

Remix:

// app/root.tsx
import { NuqsAdapter } from 'nuqs/adapters/remix'

// ...

export default function App() {
  return (
    <NuqsAdapter>
      <Outlet />
    </NuqsAdapter>
  )
}

React Router:

import { NuqsAdapter } from 'nuqs/adapters/react-router'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import App from './App'

const router = createBrowserRouter([
  {
    path: '/',
    element: <App />
  }
])

export function ReactRouter() {
  return (
    <NuqsAdapter>
      <RouterProvider router={router} />
    </NuqsAdapter>
  )
}

Closes #603, #620.

vercel[bot] commented 1 month ago

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
nuqs ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 21, 2024 8:58pm
pkg-pr-new[bot] commented 1 month ago

Open in Stackblitz

pnpm add https://pkg.pr.new/nuqs@644

commit: 35ce3f6