Skip to content

useSearchParams() instanceof ReadonlyURLSearchParams returns false on the server and true on the client. #86501

@ClementDreptin

Description

@ClementDreptin

Link to the code that reproduces this issue

https://codesandbox.io/p/devbox/adoring-nobel-36s846?file=%2Fapp%2Fclient.tsx

To Reproduce

Refresh the CodeSandbox preview and see the page content change from false to true.

Current vs. Expected behavior

According to type definitions, useSearchParams() returns a ReadonlyURLSearchParams instance. While rendering a client component on the server, useSearchParams() instanceof ReadonlyURLSearchParams returns false, but when hydration starts and the client component is rendered on the client, useSearchParams() instanceof ReadonlyURLSearchParams returns true.

This happens only while using the dev server, with the prod server, useSearchParams() instanceof ReadonlyURLSearchParams always returns true.

I expect useSearchParams() instanceof ReadonlyURLSearchParams to always return true when using the dev server.

Provide environment information

CodeSandbox environment:

Operating System:
  Platform: linux
  Arch: x64
  Version: #1 SMP PREEMPT_DYNAMIC Sun Aug  6 20:05:33 UTC 2023
  Available memory (MB): 4102
  Available CPU cores: 2
Binaries:
  Node: 20.12.1
  npm: 10.5.0
  Yarn: 1.22.19
  pnpm: 8.15.6
Relevant Packages:
  next: 16.1.0-canary.1 // Latest available version is detected (16.1.0-canary.1).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Not sure

Which stage(s) are affected? (Select all that apply)

next dev (local)

Additional context

I tested my reproduction against different canary releases, and the first one that introduced the bug was "16.0.0-canary.16", since reverting to "16.0.0-canary.15" works.

For context, I'm trying to write a SearchParams wrapper class that can take both the result of useSearchParams() or the searchParams object passed to page components in its constructor, and do different things based on what was passed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions