Skip to content

Consolidate Router State AccessΒ #13073

Open
@ryanflorence

Description

@ryanflorence

Discussed in #12358

Originally posted by ryanflorence November 23, 2024
Right now you access active, pending, and transitioning states from a bunch of different hooks. This proposal hopes to consolidate them all into a simpler API.

Today

Accessing Current States

let location = useLocation()
let params = useParams()
let [searchParams] = useSearchParams()
let matches = useMatches()
let type = useNavigationType()
<NavLink to={path}>{({ isActive }) => isActive}</NavLink>

Accessing Pending States

let navigation = useNavigation()
navigation.location

// have to construct search params
let searchParams = new URLSearchParams(
  navigation.location.search,
)

// no access
let params = undefined
let type = undefined

// access to form stuff (rarely used, fetchers usually better)
navigation.formAction // etc.
<NavLink to={path}>{({ isPending }) => isPending}</NavLink>

Accessing View Transition States

let state = useViewTransitionState(to)
<NavLink to={path}>
  {({ isTransitioning }) => isTransitioning}
</NavLink>

Proposal: Consolidate into one hook

All of those hooks are either accessing active/pending states or matching against a path and providing active/pending states. We can do this with one hook.

type RouterStateVariant = {
  location: Location
  searchParams: URLSearchParams
  params: Params
  matches: Matches
}

type RouterState = {
  active: RouterStateVariant
  pending: null | RouterStateVariant
  transitioning: boolean
}

let { active, pending, transitioning } = useRouterState()

// user clicks a link, both active and pending could have values
active.location
pending.location

By providing a path to the hook, we can match against it to determine the states, and even provide better types

type RouterStateVariant<Path> = {
  location: Location<Path>
  searchParams: URLSearchParams<Path>
  params: Params<Path>
  matches: Matches<Path>
  type: NavigationType // Pop, Push, Replace
}

type RouterState<Path> = {
  active: null | RouterStateVariant<Path>
  pending: null | RouterStateVariant<Path>
  transitioning: boolean
}

let { active, pending, transitioning } =
  useRouterState('/projects/:id')

// the url is /projects/123
active.params.id
active.location // etc.
pending === null

// the url is /projects, user clicked /projects/123
active === null
pending.params.id
pending.location

Deprecations

This one hook can deprecate all eight of these:

  • useLocation
  • useSearchParams
  • useParams
  • useTransitionState
  • useNavigation
  • useMatches
  • useMatch(pattern)
  • useNavigationType

Refactor

Probably some potential refactoring to simplify the code and have the deprecated hooks (and NavLink) use the new hook underneath.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    Status

    Planned

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions