diff --git a/packages/react-router/tests/speed.bench.tsx b/packages/react-router/tests/speed.bench.tsx new file mode 100644 index 00000000000..3a48b79b766 --- /dev/null +++ b/packages/react-router/tests/speed.bench.tsx @@ -0,0 +1,120 @@ +import { cleanup, render } from '@testing-library/react' +import { act } from 'react' +import { bench, describe } from 'vitest' +import { rootRouteId } from '@tanstack/router-core' +import { + Outlet, + RouterProvider, + createMemoryHistory, + createRootRoute, + createRoute, + createRouter, + useParams, + useSearch, +} from '../src' +import type { NavigateOptions } from '@tanstack/router-core' + +function createTestRouter() { + function runPerfSelectorComputation(seed: number) { + let value = Math.trunc(seed) | 0 + + for (let index = 0; index < 100; index++) { + value = (value * 1664525 + 1013904223 + index) >>> 0 + } + + return value + } + + const selectors = Array.from({ length: 20 }, (_, index) => index) + + function Params() { + const params = useParams({ + from: rootRouteId, + select: (params) => runPerfSelectorComputation(Number(params.id ?? 0)), + }) + void params + return null + } + + function Search() { + const search = useSearch({ + from: rootRouteId, + select: (search) => runPerfSelectorComputation(Number(search.id ?? 0)), + }) + void search + return null + } + + function Root() { + return ( + <> + {selectors.map((selector) => ( + + ))} + {selectors.map((selector) => ( + + ))} + + + ) + } + + const root = createRootRoute({ + component: Root, + }) + + const route = createRoute({ + getParentRoute: () => root, + path: '/$id', + component: () =>
, + }) + + return createRouter({ + history: createMemoryHistory({ + initialEntries: ['/0'], + }), + scrollRestoration: true, + routeTree: root.addChildren([route]), + }) +} + +describe('speed', () => { + let id = 0 + const router = createTestRouter() + let unsub = () => {} + let next: () => Promise + + bench('navigate', () => act(next), { + warmupIterations: 1000, + time: 10_000, + setup: async () => { + id = 0 + let resolve = () => {} + unsub = router.subscribe('onRendered', () => resolve()) + + const navigate = (opts: NavigateOptions) => + new Promise((resolveNext, rejectNext) => { + resolve = resolveNext + router.navigate(opts).catch(rejectNext) + }) + + next = () => { + const nextId = id++ + + return navigate({ + to: '/$id', + params: { id: nextId }, + search: { id: nextId }, + replace: true, + }) + } + + render() + await act(() => router.load()) + }, + teardown: () => { + cleanup() + unsub() + }, + }) +})