@tanstack/react-router 0.0.1-beta.215 → 0.0.1-beta.217
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.
- package/build/cjs/RouterProvider.js +41 -16
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/index.js +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/utils.js +9 -4
- package/build/cjs/utils.js.map +1 -1
- package/build/esm/index.js +50 -20
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +263 -263
- package/build/types/RouterProvider.d.ts +1 -0
- package/build/types/route.d.ts +4 -3
- package/build/types/utils.d.ts +1 -1
- package/build/umd/index.development.js +50 -20
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/RouterProvider.tsx +71 -26
- package/src/route.ts +13 -3
- package/src/utils.ts +12 -6
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/react-router",
|
|
3
3
|
"author": "Tanner Linsley",
|
|
4
|
-
"version": "0.0.1-beta.
|
|
4
|
+
"version": "0.0.1-beta.217",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "tanstack/router",
|
|
7
7
|
"homepage": "https://tanstack.com/router",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"@babel/runtime": "^7.16.7",
|
|
43
43
|
"tiny-invariant": "^1.3.1",
|
|
44
44
|
"tiny-warning": "^1.0.3",
|
|
45
|
-
"@tanstack/history": "0.0.1-beta.
|
|
45
|
+
"@tanstack/history": "0.0.1-beta.217"
|
|
46
46
|
},
|
|
47
47
|
"scripts": {
|
|
48
48
|
"build": "rollup --config rollup.config.js"
|
package/src/RouterProvider.tsx
CHANGED
|
@@ -27,7 +27,13 @@ import {
|
|
|
27
27
|
trimPathRight,
|
|
28
28
|
} from './path'
|
|
29
29
|
import { isRedirect } from './redirects'
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
AnyPathParams,
|
|
32
|
+
AnyRoute,
|
|
33
|
+
AnySearchSchema,
|
|
34
|
+
LoaderFnContext,
|
|
35
|
+
Route,
|
|
36
|
+
} from './route'
|
|
31
37
|
import {
|
|
32
38
|
FullSearchSchema,
|
|
33
39
|
ParseRoute,
|
|
@@ -51,7 +57,7 @@ import {
|
|
|
51
57
|
PickAsRequired,
|
|
52
58
|
functionalUpdate,
|
|
53
59
|
last,
|
|
54
|
-
|
|
60
|
+
deepEqual,
|
|
55
61
|
pick,
|
|
56
62
|
replaceEqualDeep,
|
|
57
63
|
useStableCallback,
|
|
@@ -486,6 +492,7 @@ export function RouterProvider<
|
|
|
486
492
|
loadPromise: Promise.resolve(),
|
|
487
493
|
context: undefined!,
|
|
488
494
|
abortController: new AbortController(),
|
|
495
|
+
shouldReloadDeps: undefined,
|
|
489
496
|
fetchedAt: 0,
|
|
490
497
|
}
|
|
491
498
|
|
|
@@ -960,22 +967,11 @@ export function RouterProvider<
|
|
|
960
967
|
if (match.isFetching) {
|
|
961
968
|
loadPromise = getRouteMatch(state, match.id)?.loadPromise
|
|
962
969
|
} else {
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
}
|
|
970
|
+
const cause = state.matches.find((d) => d.id === match.id)
|
|
971
|
+
? 'stay'
|
|
972
|
+
: 'enter'
|
|
967
973
|
|
|
968
|
-
const
|
|
969
|
-
componentTypes.map(async (type) => {
|
|
970
|
-
const component = route.options[type]
|
|
971
|
-
|
|
972
|
-
if ((component as any)?.preload) {
|
|
973
|
-
await (component as any).preload()
|
|
974
|
-
}
|
|
975
|
-
}),
|
|
976
|
-
)
|
|
977
|
-
|
|
978
|
-
const loaderPromise = route.options.loader?.({
|
|
974
|
+
const loaderContext: LoaderFnContext = {
|
|
979
975
|
params: match.params,
|
|
980
976
|
search: match.search,
|
|
981
977
|
preload: !!preload,
|
|
@@ -985,12 +981,62 @@ export function RouterProvider<
|
|
|
985
981
|
location: state.location,
|
|
986
982
|
navigate: (opts) =>
|
|
987
983
|
navigate({ ...opts, from: match.pathname } as any),
|
|
988
|
-
|
|
984
|
+
cause,
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Default to reloading the route all the time
|
|
988
|
+
let shouldReload = true
|
|
989
|
+
let shouldReloadDeps =
|
|
990
|
+
typeof route.options.shouldReload === 'function'
|
|
991
|
+
? route.options.shouldReload?.(loaderContext)
|
|
992
|
+
: !!route.options.shouldReload
|
|
993
|
+
|
|
994
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
995
|
+
// compare the deps to see if they've changed
|
|
996
|
+
shouldReload = !deepEqual(
|
|
997
|
+
shouldReloadDeps,
|
|
998
|
+
match.shouldReloadDeps,
|
|
999
|
+
)
|
|
1000
|
+
console.log(
|
|
1001
|
+
shouldReloadDeps,
|
|
1002
|
+
match.shouldReloadDeps,
|
|
1003
|
+
shouldReload,
|
|
1004
|
+
)
|
|
1005
|
+
|
|
1006
|
+
match.shouldReloadDeps = shouldReloadDeps
|
|
1007
|
+
} else {
|
|
1008
|
+
shouldReload = !!shouldReloadDeps
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// If the user doesn't want the route to reload, just
|
|
1012
|
+
// resolve with the existing loader data
|
|
1013
|
+
|
|
1014
|
+
if (!shouldReload) {
|
|
1015
|
+
loadPromise = Promise.resolve(match.loaderData)
|
|
1016
|
+
} else {
|
|
1017
|
+
// Otherwise, load the route
|
|
1018
|
+
matches[index] = match = {
|
|
1019
|
+
...match,
|
|
1020
|
+
isFetching: true,
|
|
1021
|
+
}
|
|
989
1022
|
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1023
|
+
const componentsPromise = Promise.all(
|
|
1024
|
+
componentTypes.map(async (type) => {
|
|
1025
|
+
const component = route.options[type]
|
|
1026
|
+
|
|
1027
|
+
if ((component as any)?.preload) {
|
|
1028
|
+
await (component as any).preload()
|
|
1029
|
+
}
|
|
1030
|
+
}),
|
|
1031
|
+
)
|
|
1032
|
+
|
|
1033
|
+
const loaderPromise = route.options.loader?.(loaderContext)
|
|
1034
|
+
|
|
1035
|
+
loadPromise = Promise.all([
|
|
1036
|
+
componentsPromise,
|
|
1037
|
+
loaderPromise,
|
|
1038
|
+
]).then((d) => d[1])
|
|
1039
|
+
}
|
|
994
1040
|
}
|
|
995
1041
|
|
|
996
1042
|
matches[index] = match = {
|
|
@@ -1226,7 +1272,7 @@ export function RouterProvider<
|
|
|
1226
1272
|
: true
|
|
1227
1273
|
const searchTest =
|
|
1228
1274
|
activeOptions?.includeSearch ?? true
|
|
1229
|
-
?
|
|
1275
|
+
? deepEqual(latestLocationRef.current.search, next.search, true)
|
|
1230
1276
|
: true
|
|
1231
1277
|
|
|
1232
1278
|
// The final "active" test
|
|
@@ -1381,9 +1427,7 @@ export function RouterProvider<
|
|
|
1381
1427
|
}
|
|
1382
1428
|
|
|
1383
1429
|
if (match && (opts?.includeSearch ?? true)) {
|
|
1384
|
-
return
|
|
1385
|
-
? match
|
|
1386
|
-
: false
|
|
1430
|
+
return deepEqual(baseLocation.search, next.search, true) ? match : false
|
|
1387
1431
|
}
|
|
1388
1432
|
|
|
1389
1433
|
return match
|
|
@@ -1468,6 +1512,7 @@ export interface RouteMatch<
|
|
|
1468
1512
|
search: FullSearchSchema<TRouteTree> &
|
|
1469
1513
|
RouteById<TRouteTree, TRouteId>['types']['fullSearchSchema']
|
|
1470
1514
|
fetchedAt: number
|
|
1515
|
+
shouldReloadDeps: any
|
|
1471
1516
|
abortController: AbortController
|
|
1472
1517
|
}
|
|
1473
1518
|
|
package/src/route.ts
CHANGED
|
@@ -108,6 +108,16 @@ export type BaseRouteOptions<
|
|
|
108
108
|
> = RoutePathOptions<TCustomId, TPath> & {
|
|
109
109
|
getParentRoute: () => TParentRoute
|
|
110
110
|
validateSearch?: SearchSchemaValidator<TSearchSchema>
|
|
111
|
+
shouldReload?:
|
|
112
|
+
| boolean
|
|
113
|
+
| ((
|
|
114
|
+
match: LoaderFnContext<
|
|
115
|
+
TAllParams,
|
|
116
|
+
TFullSearchSchema,
|
|
117
|
+
TAllContext,
|
|
118
|
+
TRouteContext
|
|
119
|
+
>,
|
|
120
|
+
) => any)
|
|
111
121
|
} & (keyof PickRequired<RouteContext> extends never
|
|
112
122
|
? // This async function is called before a route is loaded.
|
|
113
123
|
// If an error is thrown here, the route's loader will not be called.
|
|
@@ -268,9 +278,7 @@ export type RouteLoadFn<
|
|
|
268
278
|
TFullSearchSchema,
|
|
269
279
|
TAllContext,
|
|
270
280
|
TRouteContext
|
|
271
|
-
|
|
272
|
-
parentMatchPromise?: Promise<void>
|
|
273
|
-
},
|
|
281
|
+
>,
|
|
274
282
|
) => Promise<TLoaderData> | TLoaderData
|
|
275
283
|
|
|
276
284
|
export interface LoaderFnContext<
|
|
@@ -286,6 +294,8 @@ export interface LoaderFnContext<
|
|
|
286
294
|
context: Expand<Assign<TAllContext, TRouteContext>>
|
|
287
295
|
location: ParsedLocation<TFullSearchSchema>
|
|
288
296
|
navigate: (opts: NavigateOptions<AnyRoute>) => Promise<void>
|
|
297
|
+
parentMatchPromise?: Promise<void>
|
|
298
|
+
cause: 'enter' | 'stay'
|
|
289
299
|
}
|
|
290
300
|
|
|
291
301
|
export type SearchFilter<T, U = T> = (prev: T) => U
|
package/src/utils.ts
CHANGED
|
@@ -231,7 +231,7 @@ function hasObjectPrototype(o: any) {
|
|
|
231
231
|
return Object.prototype.toString.call(o) === '[object Object]'
|
|
232
232
|
}
|
|
233
233
|
|
|
234
|
-
export function
|
|
234
|
+
export function deepEqual(a: any, b: any, partial: boolean = false): boolean {
|
|
235
235
|
if (a === b) {
|
|
236
236
|
return true
|
|
237
237
|
}
|
|
@@ -241,14 +241,20 @@ export function partialDeepEqual(a: any, b: any): boolean {
|
|
|
241
241
|
}
|
|
242
242
|
|
|
243
243
|
if (isPlainObject(a) && isPlainObject(b)) {
|
|
244
|
-
|
|
244
|
+
const aKeys = Object.keys(a)
|
|
245
|
+
const bKeys = Object.keys(b)
|
|
246
|
+
|
|
247
|
+
if (!partial && aKeys.length !== bKeys.length) {
|
|
248
|
+
return false
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return !bKeys.some(
|
|
252
|
+
(key) => !(key in a) || !deepEqual(a[key], b[key], partial),
|
|
253
|
+
)
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
248
|
-
return !(
|
|
249
|
-
a.length !== b.length ||
|
|
250
|
-
a.some((item, index) => !partialDeepEqual(item, b[index]))
|
|
251
|
-
)
|
|
257
|
+
return !a.some((item, index) => !deepEqual(item, b[index], partial))
|
|
252
258
|
}
|
|
253
259
|
|
|
254
260
|
return false
|