pbeshai / use-query-params

React Hook for managing state in URL query parameters with easy serialization.
https://pbeshai.github.io/use-query-params
ISC License
2.13k stars 95 forks source link

React Router 6 Adapter breaks when using `createBrowserRouter` #252

Closed NerdCowboy closed 1 year ago

NerdCowboy commented 1 year ago

When using with ReactRouter6Adapter, if you use the React Router 6's object syntax with createBrowserRouter it throws an error: Uncaught TypeError: Cannot destructure property 'navigator' of '(0 , import_react.useContext)(...)' as it is null.

furkankly commented 1 year ago

This still holds, what was the reason you closed it?

NerdCowboy commented 1 year ago

Failing to remember exactly, but this was not an issue with use-query-params.

I believe the issue may have been that I didn't have the Rect RouterProvider mounted/wrapped around the QueryParamProvider

furkankly commented 1 year ago

With createBrowserRouter api we don't have a way of defining a top level QueryParamProvider as in

 <BrowserRouter>
    <QueryParamProvider 
      adapter={ReactRouter6Adapter}
    >
      <Routes>
        ......

We create a router which defines all routes as objects using createBrowserRouter and directly pass it to RouterProvider:

<RouterProvider router={router} />

I tried defining a top level layout route in router so all the routes get wrapped with the param provider:

      element: <QueryParamProvider adapter={ReactRouter6Adapter} />,
      children: [
        {
          path: '/',
          ....

but it errors with

 Property 'children' is missing in type '{ adapter: QueryParamAdapterComponent; }' but required in type '{ children: ReactNode; }'.

as adapter is implemented in a way that it needs to have children using JSX syntax.

pbeshai commented 1 year ago

You should be able to do something like the following, right?

export const router = createBrowserRouter([
  {
    path: '/',
    element: (
      <QueryParamProvider
        adapter={ReactRouter6Adapter}
        options={useQueryParamsOptions}
      >
        <Outlet />
      </QueryParamProvider>
    ),
    children: [...]
  }
]
furkankly commented 1 year ago

Ahh, I forgot adding <Outlet /> to my top level layout route. I actually don't have to bind the provider to a specific path:

const router = createBrowserRouter(
  [
    {
      element: (
        <QueryParamProvider adapter={ReactRouter6Adapter}>
          <Outlet />
        </QueryParamProvider>
      ),
      children: [
        {
        ...

works and should be equivalent of

<BrowserRouter>
    <QueryParamProvider 
      adapter={ReactRouter6Adapter}
    >
      <Routes>
        ...

Thanks for the reminder.