clear-react-router 1.0.2 → 1.0.5
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/dist/components/Link.d.ts +1 -1
- package/dist/components/Router.d.ts +1 -1
- package/dist/context/RouterContext.d.ts +5 -5
- package/dist/hooks/useBlocker.d.ts +1 -1
- package/dist/hooks/useHandleNavigation.d.ts +1 -1
- package/dist/hooks/useLatest.d.ts +1 -1
- package/dist/hooks/useLoader.d.ts +3 -3
- package/dist/hooks/useLocation.d.ts +1 -1
- package/dist/hooks/useNavigate.d.ts +1 -1
- package/dist/hooks/useServiceContext.d.ts +3 -3
- package/dist/index.d.ts +1 -2
- package/dist/index.js +28 -28
- package/dist/provider/RouterProvider.d.ts +2 -2
- package/dist/types/global.d.ts +1 -1
- package/dist/utils/createLazyComponent.d.ts +1 -1
- package/dist/utils/renderElement.d.ts +1 -1
- package/dist/utils/utils.d.ts +1 -1
- package/package.json +24 -25
- package/README.md +0 -169
- package/dist/vite.config.d.ts +0 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockerState, Location, UpdateBlockedRouteProps } from '../types/global
|
|
1
|
+
import type { BlockerState, Location, UpdateBlockedRouteProps } from '../types/global';
|
|
2
2
|
export type NavigationContextValue = {
|
|
3
3
|
location: Location;
|
|
4
4
|
params: Record<string, string>;
|
|
@@ -11,9 +11,9 @@ export type ActionsContextValue = {
|
|
|
11
11
|
setContext(arg: object): void;
|
|
12
12
|
};
|
|
13
13
|
export type DataContextValue = {
|
|
14
|
-
loaderCache:
|
|
14
|
+
loaderCache: unknown;
|
|
15
15
|
context: Record<string, unknown>;
|
|
16
16
|
};
|
|
17
|
-
export declare const ActionsContext: import(
|
|
18
|
-
export declare const DataContext: import(
|
|
19
|
-
export declare const NavigationContext: import(
|
|
17
|
+
export declare const ActionsContext: import("react").Context<ActionsContextValue>;
|
|
18
|
+
export declare const DataContext: import("react").Context<DataContextValue>;
|
|
19
|
+
export declare const NavigationContext: import("react").Context<NavigationContextValue>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BlockerState, Location, RouteItem, UpdateBlockedRouteProps } from '../types/global.ts';
|
|
1
|
+
import type { BlockerState, Location, RouteItem, UpdateBlockedRouteProps } from '../types/global.ts';
|
|
2
2
|
type UseHandleNavigation = {
|
|
3
3
|
routeList: RouteItem[];
|
|
4
4
|
setLocation: (arg: Location) => void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useLatest: <T>(value: T) => import(
|
|
1
|
+
export declare const useLatest: <T>(value: T) => import("react").RefObject<T>;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RouteItem } from '../types/global.ts';
|
|
1
|
+
import type { RouteItem } from '../types/global.ts';
|
|
2
2
|
export declare const useLoader: (routeList: RouteItem[]) => {
|
|
3
|
-
loaderCache:
|
|
3
|
+
loaderCache: unknown;
|
|
4
4
|
loaderError: boolean;
|
|
5
5
|
prefetchLoader: (pathname: string) => Promise<void>;
|
|
6
6
|
revalidateCache: (routeItem?: RouteItem) => Promise<void>;
|
|
7
|
-
|
|
7
|
+
isLoading: boolean;
|
|
8
8
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useLocation: () => import(
|
|
1
|
+
export declare const useLocation: () => import("../types/global").Location;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { Location } from '../types/global.ts';
|
|
1
|
+
import type { Location } from '../types/global.ts';
|
|
2
2
|
export declare const useNavigate: () => (arg: Location | -1) => Promise<void>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const useNavigationState: () => import(
|
|
2
|
-
export declare const useRouterActions: () => import(
|
|
3
|
-
export declare const useRouterData: () => import(
|
|
1
|
+
export declare const useNavigationState: () => import("../context/RouterContext").NavigationContextValue;
|
|
2
|
+
export declare const useRouterActions: () => import("../context/RouterContext").ActionsContextValue;
|
|
3
|
+
export declare const useRouterData: () => import("../context/RouterContext").DataContextValue;
|
package/dist/index.d.ts
CHANGED
|
@@ -7,6 +7,5 @@ export { useLoaderState } from './hooks/useLoaderState';
|
|
|
7
7
|
export { useBlocker } from './hooks/useBlocker';
|
|
8
8
|
export { useBeforeUnload } from './hooks/useBeforeUnload';
|
|
9
9
|
export { useRouterContext } from './hooks/useRouterContext';
|
|
10
|
-
export { createRouter
|
|
10
|
+
export { createRouter } from './utils/utils';
|
|
11
11
|
export { redirect } from './utils/redirect';
|
|
12
|
-
export type { ClientRouteItem, RouteItem, Location, BlockerState } from './types/global';
|
package/dist/index.js
CHANGED
|
@@ -279,15 +279,15 @@ var l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
279
279
|
})) : await f.current(e);
|
|
280
280
|
}, [l.from, f]);
|
|
281
281
|
return a(() => {
|
|
282
|
-
let
|
|
283
|
-
let
|
|
282
|
+
let e = async (e) => {
|
|
283
|
+
let t = C(e.target.location);
|
|
284
284
|
d.current === l.from ? (u({
|
|
285
285
|
from: d.current,
|
|
286
|
-
to:
|
|
287
|
-
}), history.replaceState(null, "", d.current)) :
|
|
286
|
+
to: t.pathname
|
|
287
|
+
}), history.replaceState(null, "", d.current)) : f.current(t);
|
|
288
288
|
};
|
|
289
|
-
return window.addEventListener("popstate",
|
|
290
|
-
}, [l.from,
|
|
289
|
+
return window.addEventListener("popstate", e), () => window.removeEventListener("popstate", e);
|
|
290
|
+
}, [l.from, f]), a(() => {
|
|
291
291
|
let e = C(window.location);
|
|
292
292
|
f.current(e), d.current = e.pathname;
|
|
293
293
|
}, [f]), {
|
|
@@ -296,16 +296,16 @@ var l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
296
296
|
updateBlockedRoute: p
|
|
297
297
|
};
|
|
298
298
|
}, k = (e) => {
|
|
299
|
-
let [t, n] = c({}), [i, a] = c(
|
|
299
|
+
let [t, n] = c({}), [i, a] = c(!1), [o, l] = c({}), u = s({}), d = r(({ key: e, value: t }) => n((n) => ({
|
|
300
300
|
...n,
|
|
301
301
|
[e]: t
|
|
302
302
|
})), []), f = r((e) => {
|
|
303
303
|
if (!e) return !0;
|
|
304
|
-
let t =
|
|
304
|
+
let t = u.current[e.path];
|
|
305
305
|
return !!(t && Date.now() - t < (e.staleTime || 0));
|
|
306
|
-
}, [
|
|
306
|
+
}, []), p = r(async (e) => {
|
|
307
307
|
if (e?.loader && !f(e)) {
|
|
308
|
-
|
|
308
|
+
l((t) => ({
|
|
309
309
|
...t,
|
|
310
310
|
[e.path]: !0
|
|
311
311
|
})), n((t) => Object.keys(t).filter((t) => t !== e.path).reduce((e, n) => ({
|
|
@@ -313,37 +313,37 @@ var l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
313
313
|
[n]: t[n]
|
|
314
314
|
}), {}));
|
|
315
315
|
try {
|
|
316
|
-
|
|
316
|
+
a(!1);
|
|
317
317
|
let t = await e?.loader();
|
|
318
|
-
|
|
319
|
-
...
|
|
318
|
+
u.current = {
|
|
319
|
+
...u.current,
|
|
320
320
|
[e.path]: Date.now()
|
|
321
|
-
}
|
|
321
|
+
}, d({
|
|
322
322
|
key: e.path,
|
|
323
323
|
value: t
|
|
324
324
|
});
|
|
325
325
|
} catch {
|
|
326
|
-
|
|
326
|
+
a(!0);
|
|
327
327
|
} finally {
|
|
328
|
-
|
|
328
|
+
l((t) => ({
|
|
329
329
|
...t,
|
|
330
330
|
[e.path]: !1
|
|
331
331
|
}));
|
|
332
332
|
}
|
|
333
333
|
}
|
|
334
|
-
}, [f, d])
|
|
334
|
+
}, [f, d]), m = r(async (t) => {
|
|
335
|
+
let n = e.find((e) => w(e, t));
|
|
336
|
+
n && await p(n);
|
|
337
|
+
}, [p, e]);
|
|
335
338
|
return {
|
|
336
|
-
loaderCache: t,
|
|
337
|
-
loaderError:
|
|
338
|
-
prefetchLoader:
|
|
339
|
-
let n = e.find((e) => w(e, t));
|
|
340
|
-
n && await p(n);
|
|
341
|
-
}, [p, e]),
|
|
339
|
+
loaderCache: t[window.location.pathname],
|
|
340
|
+
loaderError: i,
|
|
341
|
+
prefetchLoader: m,
|
|
342
342
|
revalidateCache: p,
|
|
343
|
-
|
|
343
|
+
isLoading: o[window.location.pathname]
|
|
344
344
|
};
|
|
345
345
|
}, A = (e) => e ? typeof e == "function" ? /* @__PURE__ */ (0, g.jsx)(e, {}) : e : null, j = "error 404. Page not found", M = "*", N = ({ routeList: e, context: t = {} }) => {
|
|
346
|
-
let [n, r] = c(C(window.location)), [i, a] = c(t), s = o(() => e.find((e) => e.path === M || w(e, n.pathname)), [n.pathname, e]), { loaderError: l, loaderCache: u, prefetchLoader: d, revalidateCache: f,
|
|
346
|
+
let [n, r] = c(C(window.location)), [i, a] = c(t), s = o(() => e.find((e) => e.path === M || w(e, n.pathname)), [n.pathname, e]), { loaderError: l, loaderCache: u, prefetchLoader: d, revalidateCache: f, isLoading: p } = k(e), { blockerState: m, updateLocation: h, updateBlockedRoute: v } = O({
|
|
347
347
|
setLocation: r,
|
|
348
348
|
routeList: e,
|
|
349
349
|
context: i,
|
|
@@ -368,7 +368,7 @@ var l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
368
368
|
v,
|
|
369
369
|
h
|
|
370
370
|
]);
|
|
371
|
-
return s?.loader && !l && p
|
|
371
|
+
return s?.loader && !l && p ? /* @__PURE__ */ (0, g.jsx)(_, {
|
|
372
372
|
...b,
|
|
373
373
|
children: A(s?.loaderFallback)
|
|
374
374
|
}) : l ? /* @__PURE__ */ (0, g.jsx)(_, {
|
|
@@ -406,7 +406,7 @@ var l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
406
406
|
return e;
|
|
407
407
|
}, B = () => P().location, V = () => {
|
|
408
408
|
let { loaderCache: e } = I();
|
|
409
|
-
return e
|
|
409
|
+
return e;
|
|
410
410
|
}, H = (e) => {
|
|
411
411
|
let { location: { pathname: t }, blockerState: n } = P(), { updateBlockedRoute: r } = F(), i = e();
|
|
412
412
|
return a(() => r(i ? {
|
|
@@ -436,4 +436,4 @@ var l = (e, t) => () => (t || (e((t = { exports: {} }).exports, t), e = null), t
|
|
|
436
436
|
};
|
|
437
437
|
};
|
|
438
438
|
//#endregion
|
|
439
|
-
export { R as Link, N as Router,
|
|
439
|
+
export { R as Link, N as Router, x as createRouter, E as redirect, U as useBeforeUnload, H as useBlocker, V as useLoaderState, B as useLocation, L as useNavigate, z as useParams, W as useRouterContext };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ReactNode } from 'react';
|
|
2
|
-
import { ActionsContextValue, DataContextValue, NavigationContextValue } from '../context/RouterContext';
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type ActionsContextValue, type DataContextValue, type NavigationContextValue } from '../context/RouterContext';
|
|
3
3
|
type RouterProviderProps = NavigationContextValue & ActionsContextValue & DataContextValue & {
|
|
4
4
|
children: ReactNode;
|
|
5
5
|
};
|
package/dist/types/global.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentType, ReactElement } from 'react';
|
|
1
|
+
import { type ComponentType, type ReactElement } from 'react';
|
|
2
2
|
export declare const createLazyComponent: (importFn: () => Promise<{
|
|
3
3
|
default: ComponentType<unknown>;
|
|
4
4
|
}>, fallback?: ReactElement | (() => ReactElement)) => (() => ReactElement);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ReactElement } from 'react';
|
|
1
|
+
import { type ReactElement } from 'react';
|
|
2
2
|
export declare const renderElement: (Component?: (() => ReactElement) | ReactElement) => import("react").JSX.Element | null;
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ClientRouteItem, Location, RouteItem } from '../types/global.ts';
|
|
1
|
+
import type { ClientRouteItem, Location, RouteItem } from '../types/global.ts';
|
|
2
2
|
export declare const createRouter: (clientList: ClientRouteItem[]) => RouteItem[];
|
|
3
3
|
export declare const getParamsObject: (params: RouteItem["params"]) => {};
|
|
4
4
|
export declare const parseWindowLocation: (location: typeof window.location) => Location;
|
package/package.json
CHANGED
|
@@ -1,32 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clear-react-router",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "A lightweight, type-safe routing library for React applications",
|
|
5
|
-
"
|
|
6
|
-
"type": "git",
|
|
7
|
-
"url": "https://github.com/AndrewBubnov/clear-react-router"
|
|
8
|
-
},
|
|
9
|
-
"sideEffects": false,
|
|
10
|
-
"type": "module",
|
|
5
|
+
"author": "Andrew Bubnov",
|
|
11
6
|
"main": "./dist/index.js",
|
|
12
7
|
"module": "./dist/index.js",
|
|
13
8
|
"types": "./dist/index.d.ts",
|
|
14
|
-
"exports": {
|
|
15
|
-
".": {
|
|
16
|
-
"import": "./dist/index.js",
|
|
17
|
-
"require": "./dist/index.js",
|
|
18
|
-
"types": "./dist/index.d.ts"
|
|
19
|
-
}
|
|
20
|
-
},
|
|
21
|
-
"files": [
|
|
22
|
-
"dist"
|
|
23
|
-
],
|
|
24
9
|
"scripts": {
|
|
25
|
-
"build": "vite build"
|
|
26
|
-
},
|
|
27
|
-
"peerDependencies": {
|
|
28
|
-
"react": ">=16.8.0",
|
|
29
|
-
"react-dom": ">=16.8.0"
|
|
10
|
+
"build": "vite build && tsc --emitDeclarationOnly"
|
|
30
11
|
},
|
|
31
12
|
"keywords": [
|
|
32
13
|
"react",
|
|
@@ -36,15 +17,33 @@
|
|
|
36
17
|
"spa",
|
|
37
18
|
"nested-routes"
|
|
38
19
|
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/AndrewBubnov/clear-react-router"
|
|
23
|
+
},
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"react": ">=16.8.0",
|
|
27
|
+
"react-dom": ">=16.8.0"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist"
|
|
31
|
+
],
|
|
39
32
|
"license": "MIT",
|
|
40
|
-
"
|
|
33
|
+
"type": "module",
|
|
34
|
+
"exports": {
|
|
35
|
+
".": {
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"import": "./dist/index.js",
|
|
38
|
+
"require": "./dist/index.js"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@types/react": "^19.2.17",
|
|
43
43
|
"@vitejs/plugin-react": "^6.0.2",
|
|
44
44
|
"react": "^19.2.7",
|
|
45
45
|
"react-dom": "^19.2.7",
|
|
46
46
|
"typescript": "^6.0.3",
|
|
47
|
-
"vite": "^8.0.16"
|
|
48
|
-
"vite-plugin-dts": "^5.0.2"
|
|
47
|
+
"vite": "^8.0.16"
|
|
49
48
|
}
|
|
50
49
|
}
|
package/README.md
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
A lightweight, type-safe routing library for React applications with nested routes, data loading, navigation blocking, and prefetching.
|
|
2
|
-
|
|
3
|
-
## Features
|
|
4
|
-
|
|
5
|
-
- 🧩 **Nested Routes** - Organize your UI with nested layouts and routes
|
|
6
|
-
- ⚡ **Data Loading** - Built-in loaders with caching and stale-while-revalidate strategy
|
|
7
|
-
- 🔒 **Navigation Blocking** - Prevent accidental navigation with `useBlocker`
|
|
8
|
-
- 🎯 **Type-safe Redirects** - Redirect from loaders and beforeLoad hooks
|
|
9
|
-
- 📦 **Prefetching** - Preload data on hover for instant navigation
|
|
10
|
-
- 🚀 **Lazy Loading** - Code-split your routes with dynamic imports for optimal performance
|
|
11
|
-
- 🎨 **Flexible API** - Use components or hooks as you prefer
|
|
12
|
-
- 📱 **Browser History** - Full support for browser back/forward buttons
|
|
13
|
-
- 🧠 **Context-aware** - Pass and update context through routes
|
|
14
|
-
|
|
15
|
-
## API
|
|
16
|
-
|
|
17
|
-
### `Router`
|
|
18
|
-
|
|
19
|
-
Main component that renders the application based on current URL.
|
|
20
|
-
|
|
21
|
-
| Prop | Type | Description |
|
|
22
|
-
|------|------|-------------|
|
|
23
|
-
| `routeList` | `RouteItem[]` | Array of route configurations |
|
|
24
|
-
| `context` | `object` | Optional initial context (user, theme, etc.) |
|
|
25
|
-
|
|
26
|
-
### `createRouter(routes)`
|
|
27
|
-
|
|
28
|
-
Normalizes route configuration. Handles wildcard `*` routes, extracts dynamic params, builds nested paths.
|
|
29
|
-
|
|
30
|
-
### `redirect(url, search?)`
|
|
31
|
-
|
|
32
|
-
Redirects from `beforeLoad`.
|
|
33
|
-
```
|
|
34
|
-
beforeLoad: context => {
|
|
35
|
-
if (!context.isAuthorized) return redirect('/');
|
|
36
|
-
}
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### `Link`
|
|
40
|
-
|
|
41
|
-
Component for client-side navigation with prefetch support.
|
|
42
|
-
|
|
43
|
-
| Prop | Type | Default |
|
|
44
|
-
|------|------|---------|
|
|
45
|
-
| `to` | `string` | required |
|
|
46
|
-
| `prefetch` | `boolean` | `true` |
|
|
47
|
-
| `children` | `ReactElement` | required |
|
|
48
|
-
|
|
49
|
-
## Hooks
|
|
50
|
-
|
|
51
|
-
### `useNavigate()`
|
|
52
|
-
|
|
53
|
-
Returns function to navigate programmatically:
|
|
54
|
-
|
|
55
|
-
- `navigate({ pathname: '/about' })` - navigate to path
|
|
56
|
-
- `navigate({ pathname: '/user/123', state: { fromDashboard: true } })` - navigate with state
|
|
57
|
-
- `navigate(-1)` - go back
|
|
58
|
-
|
|
59
|
-
**Note:** Navigation state can be accessed via `useLocation()`:
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
const navigate = useNavigate();
|
|
63
|
-
navigate({ pathname: '/profile', state: { userId: 123 } });
|
|
64
|
-
|
|
65
|
-
// In Profile component
|
|
66
|
-
const { state } = useLocation();
|
|
67
|
-
console.log(state); // { userId: 123 }
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### `useParams<T>()`
|
|
71
|
-
|
|
72
|
-
Returns route parameters object.
|
|
73
|
-
|
|
74
|
-
const params = useParams<{ userId: string }>();
|
|
75
|
-
// URL: /user/123 → params.userId === '123'
|
|
76
|
-
|
|
77
|
-
### `useLocation()`
|
|
78
|
-
|
|
79
|
-
Returns current location `{ pathname, search, state }`.
|
|
80
|
-
```
|
|
81
|
-
const { pathname, search, state } = useLocation();
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### `useLoaderState()`
|
|
85
|
-
|
|
86
|
-
Returns loaderState from current route's loader.
|
|
87
|
-
|
|
88
|
-
### `useBlocker(callback)`
|
|
89
|
-
|
|
90
|
-
Blocks navigation when callback returns `true`.
|
|
91
|
-
|
|
92
|
-
**Returns:**
|
|
93
|
-
|
|
94
|
-
| Property | Type | Description |
|
|
95
|
-
|----------|------|-------------|
|
|
96
|
-
| `state` | `'unblocked' \| 'charged' \| 'blocked'` | Current blocker state |
|
|
97
|
-
| `process()` | `() => void` | Confirm navigation and proceed |
|
|
98
|
-
| `reset()` | `() => void` | Cancel navigation |
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
const { state, process, reset } = useBlocker(() => hasUnsavedChanges);
|
|
102
|
-
|
|
103
|
-
useEffect(() => {
|
|
104
|
-
if (state === 'blocked') {
|
|
105
|
-
// Show your custom modal
|
|
106
|
-
if (confirm('Leave without saving?')) {
|
|
107
|
-
process();
|
|
108
|
-
} else {
|
|
109
|
-
reset();
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}, [state, process, reset]);
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### `useBeforeUnload(callback?)`
|
|
116
|
-
|
|
117
|
-
Executes a callback when the page is about to be closed or reloaded. Perfect for auto-saving data at the last moment.
|
|
118
|
-
|
|
119
|
-
**Parameters:**
|
|
120
|
-
|
|
121
|
-
| Parameter | Type | Description |
|
|
122
|
-
|-----------|------|-------------|
|
|
123
|
-
| `callback` | `() => void | undefined` | Function to execute before page unload (e.g., auto-save) |
|
|
124
|
-
|
|
125
|
-
**Note:** This hook does not show a browser confirmation dialog. It silently executes the callback, allowing you to save user data in the background before the page closes.
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
const [text, setText] = useState('');
|
|
129
|
-
const onSave = useCallback(() => {
|
|
130
|
-
localStorage.setItem('draft', text);
|
|
131
|
-
}, [text]);
|
|
132
|
-
|
|
133
|
-
// Auto-save when user tries to close/reload the page
|
|
134
|
-
useBeforeUnload(text ? onSave : undefined);
|
|
135
|
-
```
|
|
136
|
-
## Route Configuration
|
|
137
|
-
|
|
138
|
-
### `RouteItem`
|
|
139
|
-
|
|
140
|
-
| Property | Type | Description |
|
|
141
|
-
|----------|------|-------------|
|
|
142
|
-
| `path` | `string` | Route path, e.g., `/user/:userId` |
|
|
143
|
-
| `element` | `ReactElement \| () => ReactElement \| LazyComponent` | Component to render |
|
|
144
|
-
| `loader` | `() => Promise<unknown>` | Fetch data |
|
|
145
|
-
| `beforeLoad` | `(context) => Promise<void>` | Auth checks, redirects |
|
|
146
|
-
| `afterLoad` | `(context) => Promise<void>` | Analytics, side effects |
|
|
147
|
-
| `fallback` | `ReactElement \| () => ReactElement` | Loading fallback (for lazy loading) |
|
|
148
|
-
| `loaderFallback` | `ReactElement \| () => ReactElement` | Loading fallback (for loader) |
|
|
149
|
-
| `errorElement` | `ReactElement \| () => ReactElement` | Error fallback |
|
|
150
|
-
| `staleTime` | `number` | Cache duration in ms for loader data |
|
|
151
|
-
| `children` | `RouteItem[]` | Nested routes |
|
|
152
|
-
|
|
153
|
-
## Lazy Loading
|
|
154
|
-
|
|
155
|
-
Clear Router supports code-splitting out of the box. Simply pass a function that returns a dynamic import:
|
|
156
|
-
```
|
|
157
|
-
{
|
|
158
|
-
path: '/heavy-page',
|
|
159
|
-
element: () => import('./pages/HeavyComponent'),
|
|
160
|
-
fallback: () => <div>Loading...</div>,
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
## Requirements
|
|
165
|
-
- React 16.6+ (for React.lazy and Suspense)
|
|
166
|
-
- Use `default` export for your lazy-loaded components
|
|
167
|
-
|
|
168
|
-
## License
|
|
169
|
-
MIT
|
package/dist/vite.config.d.ts
DELETED