Skip to content

feat(react-router): useSearchState #4552

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: main
Choose a base branch
from

Conversation

Sheraff
Copy link
Contributor

@Sheraff Sheraff commented Jun 30, 2025

This is a 1st draft proposal for useSearchState: a hook designed to be used like a react useState, but manipulates route search params instead.

Example usage:

export const Route = createFileRoute('/foo')({
  validateSearch: z.object({
    bar: z.number()
  }),
  component: MyComponent,
})

const MyComponent = () => {
  const [state, setState] = useSearchState({
    from: '/foo',
    key: 'bar',
  })
  state
  // ^? number
  setState(2)
  setState(prev => prev + 1)

Comparison w/ and w/o this hook:

const Without = () => {
  const navigate = useNavigate()
  const value = useSearch({
    from: '/foo',
    select: s => s.value
  })
  const onClick = () => navigate({
    to: '.',
    from: '/foo',
    search: prev => ({...prev, value: 2 })
  })
}
const With = () => {
  const [value, setValue] = useSearchState({
    from: '/foo',
    key: 'value',
  })
  const onClick = () => setValue(2)
}

Points to address in this RFC:

  1. is it useful to have an initial argument? (we have it in our codebase at work, and never use it, i'd vote for removing it)
  2. are there options it would make sense for the setState to support?
    const [state, setState] = useSearchState({...})
    setState(value, {
     replace: false // defaults to true
     ignoreBlocker, 
     reloadDocument,
     viewTransition,
    })
  3. types currently don't support route masking (I've never used it myself). Does it make sense to support it for this hook that never touches the path?
  4. this hook calls router.navigate, should it call buildAndCommitLocation directly instead?
  5. this hook batches calls to setState in the same tick (to behave like react's setState) using queueMicrotask and accumulating values using symbol keys on the router. This might seem pretty alien, are we OK with this implementation?
  6. with this implementation, calling setState and navigate in the same tick is undefined behavior. Should we be more strict on this? (To me it doesn't really make sense to call both in the same tick)

TODO:

  • Add a useSearchState.test-d.tsx type test file
  • Docs
  • Expose hook on route object Route.useSearchState({ key: 'foo' })

Just in case, here's the support for queueMicrotask
developer mozilla org_en-US_docs_Web_API_Window_queueMicrotask

@github-actions github-actions bot added documentation Everything documentation related package: react-router labels Jun 30, 2025
Copy link

nx-cloud bot commented Jul 1, 2025

View your CI Pipeline Execution ↗ for commit 96afb1a

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 4m 50s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 29s View ↗

☁️ Nx Cloud last updated this comment at 2025-07-16 08:14:55 UTC

Copy link

pkg-pr-new bot commented Jul 1, 2025

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4552

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4552

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4552

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4552

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4552

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4552

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4552

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4552

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4552

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4552

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4552

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4552

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4552

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4552

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4552

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4552

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4552

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4552

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4552

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4552

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4552

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4552

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4552

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4552

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4552

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4552

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4552

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4552

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4552

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4552

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4552

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4552

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4552

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4552

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4552

commit: 96afb1a

@Sheraff Sheraff marked this pull request as ready for review July 16, 2025 17:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Everything documentation related package: react-router
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant