Skip to content

Commit

Permalink
perf(react-router): apply language service performance to `getRouteAp…
Browse files Browse the repository at this point in the history
…i` (#2354)
  • Loading branch information
chorobin committed Sep 17, 2024
1 parent b719c0d commit 3d66d70
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 40 deletions.
76 changes: 38 additions & 38 deletions packages/react-router/src/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -750,37 +750,21 @@ export type RouteConstraints = {
TRouteTree: AnyRoute
}

export type RouteTypesById<
TRouter extends RegisteredRouter,
TId extends RouteIds<TRouter['routeTree']>,
> = RouteById<TRouter['routeTree'], TId>['types']

export function getRouteApi<
TId extends RouteIds<RegisteredRouter['routeTree']>,
TRouter extends AnyRouter = RegisteredRouter,
TRoute extends AnyRoute = RouteById<TRouter['routeTree'], TId>,
TFullSearchSchema = TRoute['types']['fullSearchSchema'],
TAllParams = TRoute['types']['allParams'],
TAllContext = TRoute['types']['allContext'],
TLoaderDeps = TRoute['types']['loaderDeps'],
TLoaderData = TRoute['types']['loaderData'],
TRouter extends RegisteredRouter,
TId extends RouteIds<TRouter['routeTree']>,
>(id: TId) {
return new RouteApi<
TId,
TRouter,
TRoute,
TFullSearchSchema,
TAllParams,
TAllContext,
TLoaderDeps,
TLoaderData
>({ id })
return new RouteApi<TRouter, TId>({ id })
}

export class RouteApi<
TId extends RouteIds<RegisteredRouter['routeTree']>,
TRouter extends AnyRouter = RegisteredRouter,
TRoute extends AnyRoute = RouteById<TRouter['routeTree'], TId>,
TFullSearchSchema = TRoute['types']['fullSearchSchema'],
TAllParams = TRoute['types']['allParams'],
TAllContext = TRoute['types']['allContext'],
TLoaderDeps = TRoute['types']['loaderDeps'],
TLoaderData = TRoute['types']['loaderData'],
TRouter extends RegisteredRouter,
TId extends RouteIds<TRouter['routeTree']>,
> {
id: TId

Expand All @@ -801,41 +785,57 @@ export class RouteApi<
return useMatch({ select: opts?.select, from: this.id })
}

useRouteContext = <TSelected = Expand<TAllContext>>(opts?: {
select?: (s: Expand<TAllContext>) => TSelected
useRouteContext = <
TSelected = Expand<RouteTypesById<TRouter, TId>['allContext']>,
>(opts?: {
select?: (
s: Expand<RouteTypesById<TRouter, TId>['allContext']>,
) => TSelected
}): TSelected => {
return useMatch({
from: this.id,
select: (d: any) => (opts?.select ? opts.select(d.context) : d.context),
})
}

useSearch = <TSelected = Expand<TFullSearchSchema>>(opts?: {
select?: (s: Expand<TFullSearchSchema>) => TSelected
useSearch = <
TSelected = Expand<RouteTypesById<TRouter, TId>['fullSearchSchema']>,
>(opts?: {
select?: (
s: Expand<RouteTypesById<TRouter, TId>['fullSearchSchema']>,
) => TSelected
}): TSelected => {
return useSearch({ ...opts, from: this.id })
}

useParams = <TSelected = Expand<TAllParams>>(opts?: {
select?: (s: Expand<TAllParams>) => TSelected
useParams = <
TSelected = Expand<RouteTypesById<TRouter, TId>['allParams']>,
>(opts?: {
select?: (s: Expand<RouteTypesById<TRouter, TId>['allParams']>) => TSelected
}): TSelected => {
return useParams({ ...opts, from: this.id })
}

useLoaderDeps = <TSelected = TLoaderDeps>(opts?: {
select?: (s: TLoaderDeps) => TSelected
useLoaderDeps = <
TSelected = RouteTypesById<TRouter, TId>['loaderDeps'],
>(opts?: {
select?: (s: RouteTypesById<TRouter, TId>['loaderDeps']) => TSelected
}): TSelected => {
return useLoaderDeps({ ...opts, from: this.id, strict: false } as any)
}

useLoaderData = <TSelected = TLoaderData>(opts?: {
select?: (s: TLoaderData) => TSelected
useLoaderData = <
TSelected = RouteTypesById<TRouter, TId>['loaderData'],
>(opts?: {
select?: (s: RouteTypesById<TRouter, TId>['loaderData']) => TSelected
}): TSelected => {
return useLoaderData({ ...opts, from: this.id, strict: false } as any)
}

useNavigate = (): UseNavigateResult<TRoute['fullPath']> => {
return useNavigate({ from: this.id })
useNavigate = (): UseNavigateResult<
RouteTypesById<TRouter, TId>['fullPath']
> => {
return useNavigate({ from: this.id as string })
}

notFound = (opts?: NotFoundError) => {
Expand Down
37 changes: 35 additions & 2 deletions packages/react-router/tests/routeApi.test-d.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expectTypeOf, test } from 'vitest'
import { createRootRoute, createRoute, createRouter, getRouteApi } from '../src'
import type { UseNavigateResult } from '../src'
import type { MakeRouteMatch, UseNavigateResult } from '../src'

const rootRoute = createRootRoute()

Expand All @@ -23,6 +23,9 @@ const invoiceRoute = createRoute({
getParentRoute: () => invoicesRoute,
path: '$invoiceId',
validateSearch: () => ({ page: 0 }),
beforeLoad: () => ({ beforeLoadContext: 0 }),
loaderDeps: () => ({ dep: 0 }),
loader: () => ({ data: 0 }),
})

const routeTree = rootRoute.addChildren([
Expand All @@ -40,7 +43,7 @@ type ExtractDefaultFrom<T> =
T extends UseNavigateResult<infer DefaultFrom> ? DefaultFrom : never

describe('getRouteApi', () => {
const invoiceRouteApi = getRouteApi<'/invoices/$invoiceId', DefaultRouter>(
const invoiceRouteApi = getRouteApi<DefaultRouter, '/invoices/$invoiceId'>(
'/invoices/$invoiceId',
)
describe('useNavigate', () => {
Expand All @@ -52,6 +55,36 @@ describe('getRouteApi', () => {
>().toEqualTypeOf<'/invoices/$invoiceId'>()
})
})
test('useParams', () => {
expectTypeOf(invoiceRouteApi.useParams()).toEqualTypeOf<{
invoiceId: string
}>()
})
test('useContext', () => {
expectTypeOf(invoiceRouteApi.useRouteContext()).toEqualTypeOf<{
beforeLoadContext: number
}>()
})
test('useSearch', () => {
expectTypeOf(invoiceRouteApi.useSearch()).toEqualTypeOf<{
page: number
}>()
})
test('useLoaderData', () => {
expectTypeOf(invoiceRouteApi.useLoaderData()).toEqualTypeOf<{
data: number
}>()
})
test('useLoaderDeps', () => {
expectTypeOf(invoiceRouteApi.useLoaderDeps()).toEqualTypeOf<{
dep: number
}>()
})
test('useMatch', () => {
expectTypeOf(invoiceRouteApi.useMatch()).toEqualTypeOf<
MakeRouteMatch<typeof routeTree, '/invoices/$invoiceId'>
>()
})
})

describe('createRoute', () => {
Expand Down

0 comments on commit 3d66d70

Please sign in to comment.