@depup/tanstack__react-router 1.167.4-depup.0 → 1.168.1-depup.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +3 -4
  2. package/changes.json +2 -6
  3. package/dist/cjs/Match.cjs +118 -52
  4. package/dist/cjs/Match.cjs.map +1 -1
  5. package/dist/cjs/Matches.cjs +20 -20
  6. package/dist/cjs/Matches.cjs.map +1 -1
  7. package/dist/cjs/Scripts.cjs +36 -32
  8. package/dist/cjs/Scripts.cjs.map +1 -1
  9. package/dist/cjs/Transitioner.cjs +10 -16
  10. package/dist/cjs/Transitioner.cjs.map +1 -1
  11. package/dist/cjs/headContentUtils.cjs +147 -59
  12. package/dist/cjs/headContentUtils.cjs.map +1 -1
  13. package/dist/cjs/index.cjs +1 -1
  14. package/dist/cjs/index.dev.cjs +1 -1
  15. package/dist/cjs/link.cjs +34 -29
  16. package/dist/cjs/link.cjs.map +1 -1
  17. package/dist/cjs/not-found.cjs +20 -2
  18. package/dist/cjs/not-found.cjs.map +1 -1
  19. package/dist/cjs/router.cjs +2 -1
  20. package/dist/cjs/router.cjs.map +1 -1
  21. package/dist/cjs/routerStores.cjs +21 -0
  22. package/dist/cjs/routerStores.cjs.map +1 -0
  23. package/dist/cjs/routerStores.d.cts +7 -0
  24. package/dist/cjs/ssr/RouterClient.cjs +1 -1
  25. package/dist/cjs/ssr/RouterClient.cjs.map +1 -1
  26. package/dist/cjs/ssr/renderRouterToStream.cjs +2 -2
  27. package/dist/cjs/ssr/renderRouterToStream.cjs.map +1 -1
  28. package/dist/cjs/ssr/renderRouterToString.cjs +1 -1
  29. package/dist/cjs/ssr/renderRouterToString.cjs.map +1 -1
  30. package/dist/cjs/useCanGoBack.cjs +7 -2
  31. package/dist/cjs/useCanGoBack.cjs.map +1 -1
  32. package/dist/cjs/useLocation.cjs +21 -2
  33. package/dist/cjs/useLocation.cjs.map +1 -1
  34. package/dist/cjs/useMatch.cjs +29 -9
  35. package/dist/cjs/useMatch.cjs.map +1 -1
  36. package/dist/cjs/useRouterState.cjs +2 -2
  37. package/dist/cjs/useRouterState.cjs.map +1 -1
  38. package/dist/esm/Match.js +118 -52
  39. package/dist/esm/Match.js.map +1 -1
  40. package/dist/esm/Matches.js +21 -21
  41. package/dist/esm/Matches.js.map +1 -1
  42. package/dist/esm/Scripts.js +36 -32
  43. package/dist/esm/Scripts.js.map +1 -1
  44. package/dist/esm/Transitioner.js +10 -16
  45. package/dist/esm/Transitioner.js.map +1 -1
  46. package/dist/esm/headContentUtils.js +148 -60
  47. package/dist/esm/headContentUtils.js.map +1 -1
  48. package/dist/esm/index.dev.js +1 -1
  49. package/dist/esm/index.js +1 -1
  50. package/dist/esm/link.js +34 -29
  51. package/dist/esm/link.js.map +1 -1
  52. package/dist/esm/not-found.js +20 -2
  53. package/dist/esm/not-found.js.map +1 -1
  54. package/dist/esm/router.js +2 -1
  55. package/dist/esm/router.js.map +1 -1
  56. package/dist/esm/routerStores.d.ts +7 -0
  57. package/dist/esm/routerStores.js +20 -0
  58. package/dist/esm/routerStores.js.map +1 -0
  59. package/dist/esm/ssr/RouterClient.js +1 -1
  60. package/dist/esm/ssr/RouterClient.js.map +1 -1
  61. package/dist/esm/ssr/renderRouterToStream.js +2 -2
  62. package/dist/esm/ssr/renderRouterToStream.js.map +1 -1
  63. package/dist/esm/ssr/renderRouterToString.js +1 -1
  64. package/dist/esm/ssr/renderRouterToString.js.map +1 -1
  65. package/dist/esm/useCanGoBack.js +6 -2
  66. package/dist/esm/useCanGoBack.js.map +1 -1
  67. package/dist/esm/useLocation.js +20 -2
  68. package/dist/esm/useLocation.js.map +1 -1
  69. package/dist/esm/useMatch.js +29 -9
  70. package/dist/esm/useMatch.js.map +1 -1
  71. package/dist/esm/useRouterState.js +2 -2
  72. package/dist/esm/useRouterState.js.map +1 -1
  73. package/dist/llms/rules/api.d.ts +1 -1
  74. package/dist/llms/rules/api.js +3 -9
  75. package/package.json +11 -13
  76. package/src/Match.tsx +218 -78
  77. package/src/Matches.tsx +45 -25
  78. package/src/Scripts.tsx +72 -44
  79. package/src/Transitioner.tsx +24 -16
  80. package/src/headContentUtils.tsx +210 -27
  81. package/src/link.tsx +66 -71
  82. package/src/not-found.tsx +41 -4
  83. package/src/router.ts +2 -1
  84. package/src/routerStores.ts +26 -0
  85. package/src/ssr/RouterClient.tsx +1 -1
  86. package/src/ssr/renderRouterToStream.tsx +2 -2
  87. package/src/ssr/renderRouterToString.tsx +1 -1
  88. package/src/useCanGoBack.ts +14 -2
  89. package/src/useLocation.tsx +32 -5
  90. package/src/useMatch.tsx +61 -21
  91. package/src/useRouterState.tsx +4 -2
package/src/link.tsx CHANGED
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react'
2
+ import { useStore } from '@tanstack/react-store'
2
3
  import { flushSync } from 'react-dom'
3
4
  import {
4
5
  deepEqual,
@@ -9,7 +10,6 @@ import {
9
10
  removeTrailingSlash,
10
11
  } from '@tanstack/router-core'
11
12
  import { isServer } from '@tanstack/router-core/isServer'
12
- import { useRouterState } from './useRouterState'
13
13
  import { useRouter } from './useRouter'
14
14
 
15
15
  import { useForwardedRef, useIntersectionObserver } from './utils'
@@ -102,7 +102,7 @@ export function useLinkProps<
102
102
  //
103
103
  // For SSR parity (to avoid hydration errors), we still compute the link's
104
104
  // active status on the server, but we avoid creating any router-state
105
- // subscriptions by reading from `router.state` directly.
105
+ // subscriptions by reading from the location store directly.
106
106
  //
107
107
  // Note: `location.hash` is not available on the server.
108
108
  // ==========================================================================
@@ -204,7 +204,7 @@ export function useLinkProps<
204
204
  const isActive = (() => {
205
205
  if (externalLink) return false
206
206
 
207
- const currentLocation = router.state.location
207
+ const currentLocation = router.stores.location.state
208
208
 
209
209
  const exact = activeOptions?.exact ?? false
210
210
 
@@ -377,32 +377,13 @@ export function useLinkProps<
377
377
  // eslint-disable-next-line react-hooks/rules-of-hooks
378
378
  const isHydrated = useHydrated()
379
379
 
380
- // subscribe to path/search/hash/params to re-build location when they change
381
- // eslint-disable-next-line react-hooks/rules-of-hooks
382
- const currentLocationState = useRouterState({
383
- select: (s) => {
384
- const leaf = s.matches[s.matches.length - 1]
385
- return {
386
- search: leaf?.search,
387
- hash: s.location.hash,
388
- path: leaf?.pathname, // path + params
389
- }
390
- },
391
- structuralSharing: true as any,
392
- })
393
-
394
- const from = options.from
395
-
396
380
  // eslint-disable-next-line react-hooks/rules-of-hooks
397
381
  const _options = React.useMemo(
398
- () => {
399
- return { ...options, from }
400
- },
382
+ () => options,
401
383
  // eslint-disable-next-line react-hooks/exhaustive-deps
402
384
  [
403
385
  router,
404
- currentLocationState,
405
- from,
386
+ options.from,
406
387
  options._fromLocation,
407
388
  options.hash,
408
389
  options.to,
@@ -415,11 +396,18 @@ export function useLinkProps<
415
396
  )
416
397
 
417
398
  // eslint-disable-next-line react-hooks/rules-of-hooks
418
- const next = React.useMemo(
419
- () => router.buildLocation({ ..._options } as any),
420
- [router, _options],
399
+ const currentLocation = useStore(
400
+ router.stores.location,
401
+ (l) => l,
402
+ (prev, next) => prev.href === next.href,
421
403
  )
422
404
 
405
+ // eslint-disable-next-line react-hooks/rules-of-hooks
406
+ const next = React.useMemo(() => {
407
+ const opts = { _fromLocation: currentLocation, ..._options }
408
+ return router.buildLocation(opts as any)
409
+ }, [router, currentLocation, _options])
410
+
423
411
  // Use publicHref - it contains the correct href for display
424
412
  // When a rewrite changes the origin, publicHref is the full URL
425
413
  // Otherwise it's the origin-stripped path
@@ -474,54 +462,61 @@ export function useLinkProps<
474
462
  }, [to, hrefOption, router.protocolAllowlist])
475
463
 
476
464
  // eslint-disable-next-line react-hooks/rules-of-hooks
477
- const isActive = useRouterState({
478
- select: (s) => {
479
- if (externalLink) return false
480
- if (activeOptions?.exact) {
481
- const testExact = exactPathTest(
482
- s.location.pathname,
483
- next.pathname,
484
- router.basepath,
485
- )
486
- if (!testExact) {
487
- return false
488
- }
489
- } else {
490
- const currentPathSplit = removeTrailingSlash(
491
- s.location.pathname,
492
- router.basepath,
493
- )
494
- const nextPathSplit = removeTrailingSlash(
495
- next.pathname,
496
- router.basepath,
497
- )
498
-
499
- const pathIsFuzzyEqual =
500
- currentPathSplit.startsWith(nextPathSplit) &&
501
- (currentPathSplit.length === nextPathSplit.length ||
502
- currentPathSplit[nextPathSplit.length] === '/')
503
-
504
- if (!pathIsFuzzyEqual) {
505
- return false
506
- }
465
+ const isActive = React.useMemo(() => {
466
+ if (externalLink) return false
467
+ if (activeOptions?.exact) {
468
+ const testExact = exactPathTest(
469
+ currentLocation.pathname,
470
+ next.pathname,
471
+ router.basepath,
472
+ )
473
+ if (!testExact) {
474
+ return false
507
475
  }
508
-
509
- if (activeOptions?.includeSearch ?? true) {
510
- const searchTest = deepEqual(s.location.search, next.search, {
511
- partial: !activeOptions?.exact,
512
- ignoreUndefined: !activeOptions?.explicitUndefined,
513
- })
514
- if (!searchTest) {
515
- return false
516
- }
476
+ } else {
477
+ const currentPathSplit = removeTrailingSlash(
478
+ currentLocation.pathname,
479
+ router.basepath,
480
+ )
481
+ const nextPathSplit = removeTrailingSlash(next.pathname, router.basepath)
482
+
483
+ const pathIsFuzzyEqual =
484
+ currentPathSplit.startsWith(nextPathSplit) &&
485
+ (currentPathSplit.length === nextPathSplit.length ||
486
+ currentPathSplit[nextPathSplit.length] === '/')
487
+
488
+ if (!pathIsFuzzyEqual) {
489
+ return false
517
490
  }
491
+ }
518
492
 
519
- if (activeOptions?.includeHash) {
520
- return isHydrated && s.location.hash === next.hash
493
+ if (activeOptions?.includeSearch ?? true) {
494
+ const searchTest = deepEqual(currentLocation.search, next.search, {
495
+ partial: !activeOptions?.exact,
496
+ ignoreUndefined: !activeOptions?.explicitUndefined,
497
+ })
498
+ if (!searchTest) {
499
+ return false
521
500
  }
522
- return true
523
- },
524
- })
501
+ }
502
+
503
+ if (activeOptions?.includeHash) {
504
+ return isHydrated && currentLocation.hash === next.hash
505
+ }
506
+ return true
507
+ }, [
508
+ activeOptions?.exact,
509
+ activeOptions?.explicitUndefined,
510
+ activeOptions?.includeHash,
511
+ activeOptions?.includeSearch,
512
+ currentLocation,
513
+ externalLink,
514
+ isHydrated,
515
+ next.hash,
516
+ next.pathname,
517
+ next.search,
518
+ router.basepath,
519
+ ])
525
520
 
526
521
  // Get the active props
527
522
  const resolvedActiveProps: React.HTMLAttributes<HTMLAnchorElement> = isActive
package/src/not-found.tsx CHANGED
@@ -1,7 +1,9 @@
1
1
  import * as React from 'react'
2
2
  import { isNotFound } from '@tanstack/router-core'
3
+ import { isServer } from '@tanstack/router-core/isServer'
4
+ import { useStore } from '@tanstack/react-store'
3
5
  import { CatchBoundary } from './CatchBoundary'
4
- import { useRouterState } from './useRouterState'
6
+ import { useRouter } from './useRouter'
5
7
  import type { ErrorInfo } from 'react'
6
8
  import type { NotFoundError } from '@tanstack/router-core'
7
9
 
@@ -10,10 +12,45 @@ export function CatchNotFound(props: {
10
12
  onCatch?: (error: Error, errorInfo: ErrorInfo) => void
11
13
  children: React.ReactNode
12
14
  }) {
15
+ const router = useRouter()
16
+
17
+ if (isServer ?? router.isServer) {
18
+ const pathname = router.stores.location.state.pathname
19
+ const status = router.stores.status.state
20
+ const resetKey = `not-found-${pathname}-${status}`
21
+
22
+ return (
23
+ <CatchBoundary
24
+ getResetKey={() => resetKey}
25
+ onCatch={(error, errorInfo) => {
26
+ if (isNotFound(error)) {
27
+ props.onCatch?.(error, errorInfo)
28
+ } else {
29
+ throw error
30
+ }
31
+ }}
32
+ errorComponent={({ error }) => {
33
+ if (isNotFound(error)) {
34
+ return props.fallback?.(error)
35
+ } else {
36
+ throw error
37
+ }
38
+ }}
39
+ >
40
+ {props.children}
41
+ </CatchBoundary>
42
+ )
43
+ }
44
+
13
45
  // TODO: Some way for the user to programmatically reset the not-found boundary?
14
- const resetKey = useRouterState({
15
- select: (s) => `not-found-${s.location.pathname}-${s.status}`,
16
- })
46
+ // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static
47
+ const pathname = useStore(
48
+ router.stores.location,
49
+ (location) => location.pathname,
50
+ )
51
+ // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static
52
+ const status = useStore(router.stores.status, (status) => status)
53
+ const resetKey = `not-found-${pathname}-${status}`
17
54
 
18
55
  return (
19
56
  <CatchBoundary
package/src/router.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { RouterCore } from '@tanstack/router-core'
2
2
  import { createFileRoute, createLazyFileRoute } from './fileRoute'
3
+ import { getStoreFactory } from './routerStores'
3
4
  import type { RouterHistory } from '@tanstack/history'
4
5
  import type {
5
6
  AnyRoute,
@@ -114,7 +115,7 @@ export class Router<
114
115
  TDehydrated
115
116
  >,
116
117
  ) {
117
- super(options)
118
+ super(options, getStoreFactory)
118
119
  }
119
120
  }
120
121
 
@@ -0,0 +1,26 @@
1
+ import { batch, createStore } from '@tanstack/react-store'
2
+ import {
3
+ createNonReactiveMutableStore,
4
+ createNonReactiveReadonlyStore,
5
+ } from '@tanstack/router-core'
6
+ import { isServer } from '@tanstack/router-core/isServer'
7
+ import type { Readable } from '@tanstack/react-store'
8
+ import type { GetStoreConfig } from '@tanstack/router-core'
9
+
10
+ declare module '@tanstack/router-core' {
11
+ export interface RouterReadableStore<TValue> extends Readable<TValue> {}
12
+ }
13
+ export const getStoreFactory: GetStoreConfig = (opts) => {
14
+ if (isServer ?? opts.isServer) {
15
+ return {
16
+ createMutableStore: createNonReactiveMutableStore,
17
+ createReadonlyStore: createNonReactiveReadonlyStore,
18
+ batch: (fn) => fn(),
19
+ }
20
+ }
21
+ return {
22
+ createMutableStore: createStore,
23
+ createReadonlyStore: createStore,
24
+ batch: batch,
25
+ }
26
+ }
@@ -7,7 +7,7 @@ let hydrationPromise: Promise<void | Array<Array<void>>> | undefined
7
7
 
8
8
  export function RouterClient(props: { router: AnyRouter }) {
9
9
  if (!hydrationPromise) {
10
- if (!props.router.state.matches.length) {
10
+ if (!props.router.stores.matchesId.state.length) {
11
11
  hydrationPromise = hydrate(props.router)
12
12
  } else {
13
13
  hydrationPromise = Promise.resolve()
@@ -36,7 +36,7 @@ export const renderRouterToStream = async ({
36
36
  stream as unknown as ReadableStream,
37
37
  )
38
38
  return new Response(responseStream as any, {
39
- status: router.state.statusCode,
39
+ status: router.stores.statusCode.state,
40
40
  headers: responseHeaders,
41
41
  })
42
42
  }
@@ -79,7 +79,7 @@ export const renderRouterToStream = async ({
79
79
  reactAppPassthrough,
80
80
  )
81
81
  return new Response(responseStream as any, {
82
- status: router.state.statusCode,
82
+ status: router.stores.statusCode.state,
83
83
  headers: responseHeaders,
84
84
  })
85
85
  }
@@ -21,7 +21,7 @@ export const renderRouterToString = async ({
21
21
  }
22
22
 
23
23
  return new Response(`<!DOCTYPE html>${html}`, {
24
- status: router.state.statusCode,
24
+ status: router.stores.statusCode.state,
25
25
  headers: responseHeaders,
26
26
  })
27
27
  } catch (error) {
@@ -1,5 +1,17 @@
1
- import { useRouterState } from './useRouterState'
1
+ import { useStore } from '@tanstack/react-store'
2
+ import { isServer } from '@tanstack/router-core/isServer'
3
+ import { useRouter } from './useRouter'
2
4
 
3
5
  export function useCanGoBack() {
4
- return useRouterState({ select: (s) => s.location.state.__TSR_index !== 0 })
6
+ const router = useRouter()
7
+
8
+ if (isServer ?? router.isServer) {
9
+ return router.stores.location.state.state.__TSR_index !== 0
10
+ }
11
+
12
+ // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static
13
+ return useStore(
14
+ router.stores.location,
15
+ (location) => location.state.__TSR_index !== 0,
16
+ )
5
17
  }
@@ -1,4 +1,8 @@
1
- import { useRouterState } from './useRouterState'
1
+ import { useStore } from '@tanstack/react-store'
2
+ import { useRef } from 'react'
3
+ import { replaceEqualDeep } from '@tanstack/router-core'
4
+ import { isServer } from '@tanstack/router-core/isServer'
5
+ import { useRouter } from './useRouter'
2
6
  import type {
3
7
  StructuralSharingOption,
4
8
  ValidateSelected,
@@ -45,8 +49,31 @@ export function useLocation<
45
49
  opts?: UseLocationBaseOptions<TRouter, TSelected, TStructuralSharing> &
46
50
  StructuralSharingOption<TRouter, TSelected, TStructuralSharing>,
47
51
  ): UseLocationResult<TRouter, TSelected> {
48
- return useRouterState({
49
- select: (state: any) =>
50
- opts?.select ? opts.select(state.location) : state.location,
51
- } as any) as UseLocationResult<TRouter, TSelected>
52
+ const router = useRouter<TRouter>()
53
+
54
+ if (isServer ?? router.isServer) {
55
+ const location = router.stores.location.state
56
+ return (
57
+ opts?.select ? opts.select(location as any) : location
58
+ ) as UseLocationResult<TRouter, TSelected>
59
+ }
60
+
61
+ const previousResult =
62
+ // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static
63
+ useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined)
64
+
65
+ // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static
66
+ return useStore(router.stores.location, (location) => {
67
+ const selected = (
68
+ opts?.select ? opts.select(location as any) : location
69
+ ) as ValidateSelected<TRouter, TSelected, TStructuralSharing>
70
+
71
+ if (opts?.structuralSharing ?? router.options.defaultStructuralSharing) {
72
+ const shared = replaceEqualDeep(previousResult.current, selected)
73
+ previousResult.current = shared
74
+ return shared
75
+ }
76
+
77
+ return selected
78
+ }) as UseLocationResult<TRouter, TSelected>
52
79
  }
package/src/useMatch.tsx CHANGED
@@ -1,7 +1,10 @@
1
1
  import * as React from 'react'
2
+ import { useStore } from '@tanstack/react-store'
3
+ import { replaceEqualDeep } from '@tanstack/router-core'
4
+ import { isServer } from '@tanstack/router-core/isServer'
2
5
  import invariant from 'tiny-invariant'
3
- import { useRouterState } from './useRouterState'
4
6
  import { dummyMatchContext, matchContext } from './matchContext'
7
+ import { useRouter } from './useRouter'
5
8
  import type {
6
9
  StructuralSharingOption,
7
10
  ValidateSelected,
@@ -16,6 +19,12 @@ import type {
16
19
  ThrowOrOptional,
17
20
  } from '@tanstack/router-core'
18
21
 
22
+ const dummyStore = {
23
+ state: undefined,
24
+ get: () => undefined,
25
+ subscribe: () => () => {},
26
+ } as any
27
+
19
28
  export interface UseMatchBaseOptions<
20
29
  TRouter extends AnyRouter,
21
30
  TFrom,
@@ -96,28 +105,59 @@ export function useMatch<
96
105
  TStructuralSharing
97
106
  >,
98
107
  ): ThrowOrOptional<UseMatchResult<TRouter, TFrom, TStrict, TSelected>, TThrow> {
108
+ const router = useRouter<TRouter>()
99
109
  const nearestMatchId = React.useContext(
100
110
  opts.from ? dummyMatchContext : matchContext,
101
111
  )
102
112
 
103
- const matchSelection = useRouterState({
104
- select: (state: any) => {
105
- const match = state.matches.find((d: any) =>
106
- opts.from ? opts.from === d.routeId : d.id === nearestMatchId,
107
- )
108
- invariant(
109
- !((opts.shouldThrow ?? true) && !match),
110
- `Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`,
111
- )
112
-
113
- if (match === undefined) {
114
- return undefined
115
- }
116
-
117
- return opts.select ? opts.select(match) : match
118
- },
119
- structuralSharing: opts.structuralSharing,
120
- } as any)
121
-
122
- return matchSelection as any
113
+ const key = opts.from ?? nearestMatchId
114
+ const matchStore = key
115
+ ? opts.from
116
+ ? router.stores.getMatchStoreByRouteId(key)
117
+ : router.stores.activeMatchStoresById.get(key)
118
+ : undefined
119
+
120
+ if (isServer ?? router.isServer) {
121
+ const match = matchStore?.state
122
+ invariant(
123
+ !((opts.shouldThrow ?? true) && !match),
124
+ `Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`,
125
+ )
126
+
127
+ if (match === undefined) {
128
+ return undefined as any
129
+ }
130
+
131
+ return (opts.select ? opts.select(match as any) : match) as any
132
+ }
133
+
134
+ const previousResult =
135
+ // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static
136
+ React.useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(
137
+ undefined,
138
+ )
139
+
140
+ // eslint-disable-next-line react-hooks/rules-of-hooks -- condition is static
141
+ return useStore(matchStore ?? dummyStore, (match) => {
142
+ invariant(
143
+ !((opts.shouldThrow ?? true) && !match),
144
+ `Could not find ${opts.from ? `an active match from "${opts.from}"` : 'a nearest match!'}`,
145
+ )
146
+
147
+ if (match === undefined) {
148
+ return undefined
149
+ }
150
+
151
+ const selected = (
152
+ opts.select ? opts.select(match as any) : match
153
+ ) as ValidateSelected<TRouter, TSelected, TStructuralSharing>
154
+
155
+ if (opts.structuralSharing ?? router.options.defaultStructuralSharing) {
156
+ const shared = replaceEqualDeep(previousResult.current, selected)
157
+ previousResult.current = shared
158
+ return shared
159
+ }
160
+
161
+ return selected
162
+ }) as any
123
163
  }
@@ -57,7 +57,9 @@ export function useRouterState<
57
57
  // Avoid subscribing to the store (and any structural sharing work) on the server.
58
58
  const _isServer = isServer ?? router.isServer
59
59
  if (_isServer) {
60
- const state = router.state as RouterState<TRouter['routeTree']>
60
+ const state = router.stores.__store.state as RouterState<
61
+ TRouter['routeTree']
62
+ >
61
63
  return (opts?.select ? opts.select(state) : state) as UseRouterStateResult<
62
64
  TRouter,
63
65
  TSelected
@@ -69,7 +71,7 @@ export function useRouterState<
69
71
  useRef<ValidateSelected<TRouter, TSelected, TStructuralSharing>>(undefined)
70
72
 
71
73
  // eslint-disable-next-line react-hooks/rules-of-hooks
72
- return useStore(router.__store, (state) => {
74
+ return useStore(router.stores.__store, (state) => {
73
75
  if (opts?.select) {
74
76
  if (opts.structuralSharing ?? router.options.defaultStructuralSharing) {
75
77
  const newSlice = replaceEqualDeep(