@real-router/react 0.12.2 → 0.12.3
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/README.md +93 -243
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,284 +1,123 @@
|
|
|
1
1
|
# @real-router/react
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@real-router/react)
|
|
4
|
+
[](https://www.npmjs.com/package/@real-router/react)
|
|
5
|
+
[](https://bundlejs.com/?q=@real-router/react&treeshake=[*])
|
|
6
|
+
[](../../LICENSE)
|
|
5
7
|
|
|
6
|
-
React integration for Real-Router — hooks, components, and context providers.
|
|
8
|
+
> React integration for [Real-Router](https://github.com/greydragon888/real-router) — hooks, components, and context providers.
|
|
7
9
|
|
|
8
10
|
## Installation
|
|
9
11
|
|
|
10
12
|
```bash
|
|
11
13
|
npm install @real-router/react @real-router/core @real-router/browser-plugin
|
|
12
|
-
# or
|
|
13
|
-
pnpm add @real-router/react @real-router/core @real-router/browser-plugin
|
|
14
|
-
# or
|
|
15
|
-
yarn add @real-router/react @real-router/core @real-router/browser-plugin
|
|
16
|
-
# or
|
|
17
|
-
bun add @real-router/react @real-router/core @real-router/browser-plugin
|
|
18
14
|
```
|
|
19
15
|
|
|
20
|
-
**Peer
|
|
16
|
+
**Peer dependency:** `react` >= 18.0.0
|
|
21
17
|
|
|
22
18
|
## Entry Points
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
| Import Path | React Version | Includes |
|
|
21
|
+
|-------------|---------------|----------|
|
|
22
|
+
| `@real-router/react` | 19.2+ | Full API (hooks, `Link`, `RouteView` with `keepAlive`) |
|
|
23
|
+
| `@real-router/react/legacy` | 18+ | All hooks and `Link`, no `RouteView` |
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
| --------------------------- | ------------- | ----------------------------------------- |
|
|
28
|
-
| `@real-router/react` | 19.2+ | Full API (default) |
|
|
29
|
-
| `@real-router/react/legacy` | 18+ | Same API minus React 19.2-only components |
|
|
30
|
-
|
|
31
|
-
```tsx
|
|
32
|
-
// React 19.2+ (default) — full API
|
|
33
|
-
import { RouterProvider, useRouteNode, Link } from "@real-router/react";
|
|
34
|
-
|
|
35
|
-
// React 18+ — without React 19.2-only components
|
|
36
|
-
import { RouterProvider, useRouteNode, Link } from "@real-router/react/legacy";
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Both entry points share the same underlying code — `/legacy` is a re-export subset that excludes components requiring React 19.2+ APIs (e.g., `<Activity>`).
|
|
25
|
+
Both share the same underlying code — `/legacy` excludes components that require React 19.2's `<Activity>` API.
|
|
40
26
|
|
|
41
27
|
## Quick Start
|
|
42
28
|
|
|
43
29
|
```tsx
|
|
44
30
|
import { createRouter } from "@real-router/core";
|
|
45
31
|
import { browserPluginFactory } from "@real-router/browser-plugin";
|
|
46
|
-
import { RouterProvider,
|
|
47
|
-
import { createRoot } from "react-dom/client";
|
|
32
|
+
import { RouterProvider, RouteView, Link } from "@real-router/react";
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
const routes = [
|
|
34
|
+
const router = createRouter([
|
|
51
35
|
{ name: "home", path: "/" },
|
|
52
|
-
{
|
|
53
|
-
name: "
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
];
|
|
58
|
-
|
|
59
|
-
// Create and configure router
|
|
60
|
-
const router = createRouter(routes);
|
|
36
|
+
{ name: "users", path: "/users", children: [
|
|
37
|
+
{ name: "profile", path: "/:id" },
|
|
38
|
+
]},
|
|
39
|
+
]);
|
|
40
|
+
|
|
61
41
|
router.usePlugin(browserPluginFactory());
|
|
62
42
|
router.start();
|
|
63
43
|
|
|
64
|
-
// App component
|
|
65
44
|
function App() {
|
|
66
|
-
const { route } = useRoute();
|
|
67
|
-
|
|
68
45
|
return (
|
|
69
|
-
<
|
|
46
|
+
<RouterProvider router={router}>
|
|
70
47
|
<nav>
|
|
71
48
|
<Link routeName="home">Home</Link>
|
|
72
49
|
<Link routeName="users">Users</Link>
|
|
73
50
|
</nav>
|
|
74
|
-
<
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
51
|
+
<RouteView nodeName="">
|
|
52
|
+
<RouteView.Match routeName="home"><HomePage /></RouteView.Match>
|
|
53
|
+
<RouteView.Match routeName="users"><UsersPage /></RouteView.Match>
|
|
54
|
+
<RouteView.NotFound><NotFoundPage /></RouteView.NotFound>
|
|
55
|
+
</RouteView>
|
|
56
|
+
</RouterProvider>
|
|
78
57
|
);
|
|
79
58
|
}
|
|
80
|
-
|
|
81
|
-
createRoot(document.getElementById("root")!).render(
|
|
82
|
-
<RouterProvider router={router}>
|
|
83
|
-
<App />
|
|
84
|
-
</RouterProvider>,
|
|
85
|
-
);
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
---
|
|
89
|
-
|
|
90
|
-
## API
|
|
91
|
-
|
|
92
|
-
### Provider
|
|
93
|
-
|
|
94
|
-
#### `<RouterProvider router={router}>`
|
|
95
|
-
|
|
96
|
-
Provides router instance to component tree via React Context.\
|
|
97
|
-
`router: Router` — router instance from `createRouter()`\
|
|
98
|
-
`children: ReactNode` — child components\
|
|
99
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/RouterProvider)
|
|
100
|
-
|
|
101
|
-
```tsx
|
|
102
|
-
<RouterProvider router={router}>
|
|
103
|
-
<App />
|
|
104
|
-
</RouterProvider>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
### Hooks
|
|
110
|
-
|
|
111
|
-
#### `useRouter(): Router`
|
|
112
|
-
|
|
113
|
-
Get router instance. **Never re-renders** on navigation.\
|
|
114
|
-
Returns: `Router` — router instance\
|
|
115
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/useRouter)
|
|
116
|
-
|
|
117
|
-
```tsx
|
|
118
|
-
import { useRouter } from "@real-router/react";
|
|
119
|
-
|
|
120
|
-
const NavigateButton = () => {
|
|
121
|
-
const router = useRouter();
|
|
122
|
-
|
|
123
|
-
return <button onClick={() => router.navigate("home")}>Go Home</button>;
|
|
124
|
-
};
|
|
125
59
|
```
|
|
126
60
|
|
|
127
|
-
|
|
61
|
+
## Hooks
|
|
128
62
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
63
|
+
| Hook | Returns | Re-renders |
|
|
64
|
+
|------|---------|------------|
|
|
65
|
+
| `useRouter()` | `Router` | Never |
|
|
66
|
+
| `useNavigator()` | `Navigator` | Never (stable ref, safe to destructure) |
|
|
67
|
+
| `useRoute()` | `{ router, route, previousRoute }` | Every navigation |
|
|
68
|
+
| `useRouteNode(name)` | `{ router, route, previousRoute }` | Only when node activates/deactivates |
|
|
69
|
+
| `useRouteUtils()` | `RouteUtils` | Never |
|
|
70
|
+
| `useRouterTransition()` | `{ isTransitioning, toRoute, fromRoute }` | On transition start/end |
|
|
132
71
|
|
|
133
72
|
```tsx
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
const
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<div>
|
|
141
|
-
<p>Current: {route?.name}</p>
|
|
142
|
-
<p>Previous: {previousRoute?.name}</p>
|
|
143
|
-
<p>Params: {JSON.stringify(route?.params)}</p>
|
|
144
|
-
<button onClick={() => router.navigate("home")}>Go Home</button>
|
|
145
|
-
</div>
|
|
146
|
-
);
|
|
147
|
-
};
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
#### `useRouteNode(nodeName: string): { router, route, previousRoute }`
|
|
151
|
-
|
|
152
|
-
Optimized hook for nested routes. **Re-renders only when specified node changes.**\
|
|
153
|
-
`nodeName: string` — route segment to observe (e.g., `"users"`)
|
|
154
|
-
Returns: `{ router: Router, route: State | undefined, previousRoute: State | undefined }`\
|
|
155
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/useRouteNode)
|
|
156
|
-
|
|
157
|
-
```tsx
|
|
158
|
-
import { useRouteNode } from "@real-router/react";
|
|
159
|
-
|
|
160
|
-
const UsersSection = () => {
|
|
161
|
-
// Only re-renders when routes starting with "users" change
|
|
162
|
-
const { router, route, previousRoute } = useRouteNode("users");
|
|
163
|
-
|
|
164
|
-
// route is undefined when current route is NOT under "users" node
|
|
165
|
-
if (!route) {
|
|
166
|
-
return null;
|
|
167
|
-
}
|
|
73
|
+
// useRouteNode — re-renders only when "users.*" changes
|
|
74
|
+
function UsersLayout() {
|
|
75
|
+
const { route } = useRouteNode("users");
|
|
76
|
+
if (!route) return null;
|
|
168
77
|
|
|
169
78
|
switch (route.name) {
|
|
170
|
-
case "users":
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
return <UserProfile id={route.params.id} />;
|
|
174
|
-
default:
|
|
175
|
-
return null;
|
|
79
|
+
case "users": return <UsersList />;
|
|
80
|
+
case "users.profile": return <UserProfile id={route.params.id} />;
|
|
81
|
+
default: return null;
|
|
176
82
|
}
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
#### `useRouteUtils(): RouteUtils`
|
|
181
|
-
|
|
182
|
-
Get pre-computed route tree query utilities. **Never re-renders** on navigation.\
|
|
183
|
-
Returns: `RouteUtils` — cached instance with chain, sibling, and descendant lookups\
|
|
184
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/useRouteUtils)
|
|
185
|
-
|
|
186
|
-
```tsx
|
|
187
|
-
import { useRouteUtils } from "@real-router/react";
|
|
188
|
-
|
|
189
|
-
const Breadcrumbs = () => {
|
|
190
|
-
const utils = useRouteUtils();
|
|
191
|
-
const chain = utils.getChain("users.profile");
|
|
192
|
-
// → ["users", "users.profile"]
|
|
193
|
-
|
|
194
|
-
return (
|
|
195
|
-
<nav>
|
|
196
|
-
{chain?.map((segment) => (
|
|
197
|
-
<span key={segment}>{segment}</span>
|
|
198
|
-
))}
|
|
199
|
-
</nav>
|
|
200
|
-
);
|
|
201
|
-
};
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
#### `useRouterTransition(): RouterTransitionSnapshot`
|
|
205
|
-
|
|
206
|
-
Track router transition lifecycle (start/success/error/cancel). **Re-renders on transition start and end.**\
|
|
207
|
-
Returns: `RouterTransitionSnapshot` — `{ isTransitioning: boolean, toRoute: State | null, fromRoute: State | null }`
|
|
208
|
-
|
|
209
|
-
```tsx
|
|
210
|
-
import { useRouterTransition } from "@real-router/react";
|
|
83
|
+
}
|
|
211
84
|
|
|
212
|
-
|
|
213
|
-
|
|
85
|
+
// useNavigator — stable reference, never causes re-renders
|
|
86
|
+
function BackButton() {
|
|
87
|
+
const navigator = useNavigator();
|
|
88
|
+
return <button onClick={() => navigator.navigate("home")}>Back</button>;
|
|
89
|
+
}
|
|
214
90
|
|
|
91
|
+
// useRouterTransition — progress bars, loading states
|
|
92
|
+
function GlobalProgress() {
|
|
93
|
+
const { isTransitioning } = useRouterTransition();
|
|
215
94
|
if (!isTransitioning) return null;
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
<div className="progress-bar">
|
|
219
|
-
Navigating from {fromRoute?.name} to {toRoute?.name}…
|
|
220
|
-
</div>
|
|
221
|
-
);
|
|
222
|
-
};
|
|
95
|
+
return <div className="progress-bar" />;
|
|
96
|
+
}
|
|
223
97
|
```
|
|
224
98
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
---
|
|
99
|
+
## Components
|
|
228
100
|
|
|
229
|
-
###
|
|
101
|
+
### `<Link>`
|
|
230
102
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
Navigation link with automatic active state detection. Re-renders only when its own active status changes.\
|
|
234
|
-
`routeName: string` — target route name\
|
|
235
|
-
`routeParams?: Params` — route parameters\
|
|
236
|
-
`routeOptions?: { reload?, replace? }` — navigation options\
|
|
237
|
-
`activeClassName?: string` — class when active (default: `"active"`)
|
|
238
|
-
`activeStrict?: boolean` — exact match only (default: `false`)
|
|
239
|
-
`ignoreQueryParams?: boolean` — ignore query params in active check (default: `true`)\
|
|
240
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/Link)
|
|
103
|
+
Navigation link with automatic active state detection. Re-renders only when its active status changes.
|
|
241
104
|
|
|
242
105
|
```tsx
|
|
243
|
-
import { Link } from "@real-router/react";
|
|
244
|
-
|
|
245
106
|
<Link
|
|
246
107
|
routeName="users.profile"
|
|
247
108
|
routeParams={{ id: "123" }}
|
|
248
|
-
activeClassName="active"
|
|
249
|
-
activeStrict={false}
|
|
109
|
+
activeClassName="active" // default: "active"
|
|
110
|
+
activeStrict={false} // default: false (ancestor match)
|
|
111
|
+
ignoreQueryParams={true} // default: true
|
|
112
|
+
routeOptions={{ replace: true }}
|
|
250
113
|
>
|
|
251
114
|
View Profile
|
|
252
|
-
</Link
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
#### `<RouteView nodeName={string}>`
|
|
256
|
-
|
|
257
|
-
Declarative route matching component. Subscribes to a route node and renders the first matched segment.\
|
|
258
|
-
`nodeName: string` — route node to subscribe to (`""` for root)\
|
|
259
|
-
[Wiki](https://github.com/greydragon888/real-router/wiki/RouteView)
|
|
260
|
-
|
|
261
|
-
> **Note:** `RouteView` is only available from the main entry point (`@real-router/react`). It requires React 19.2+ for `keepAlive` support via `<Activity>`.
|
|
262
|
-
|
|
263
|
-
```tsx
|
|
264
|
-
import { RouteView } from "@real-router/react";
|
|
265
|
-
|
|
266
|
-
<RouteView nodeName="">
|
|
267
|
-
<RouteView.Match segment="users">
|
|
268
|
-
<UsersPage />
|
|
269
|
-
</RouteView.Match>
|
|
270
|
-
<RouteView.Match segment="settings">
|
|
271
|
-
<SettingsPage />
|
|
272
|
-
</RouteView.Match>
|
|
273
|
-
<RouteView.NotFound>
|
|
274
|
-
<NotFoundPage />
|
|
275
|
-
</RouteView.NotFound>
|
|
276
|
-
</RouteView>;
|
|
115
|
+
</Link>
|
|
277
116
|
```
|
|
278
117
|
|
|
279
|
-
|
|
118
|
+
### `<RouteView>` (React 19.2+)
|
|
280
119
|
|
|
281
|
-
|
|
120
|
+
Declarative route matching with optional `keepAlive` — preserves component state via React's `<Activity>` API.
|
|
282
121
|
|
|
283
122
|
```tsx
|
|
284
123
|
<RouteView nodeName="">
|
|
@@ -288,43 +127,54 @@ import { RouteView } from "@real-router/react";
|
|
|
288
127
|
<RouteView.Match segment="settings">
|
|
289
128
|
<SettingsPage /> {/* Unmounts normally */}
|
|
290
129
|
</RouteView.Match>
|
|
130
|
+
<RouteView.NotFound>
|
|
131
|
+
<NotFoundPage />
|
|
132
|
+
</RouteView.NotFound>
|
|
291
133
|
</RouteView>
|
|
292
134
|
```
|
|
293
135
|
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
---
|
|
297
|
-
|
|
298
|
-
## Migration from React 18
|
|
136
|
+
## React 18 Migration
|
|
299
137
|
|
|
300
|
-
|
|
138
|
+
One import path change — all hooks and `Link` work identically:
|
|
301
139
|
|
|
302
140
|
```diff
|
|
303
141
|
- import { useRouteNode, Link } from '@real-router/react';
|
|
304
142
|
+ import { useRouteNode, Link } from '@real-router/react/legacy';
|
|
305
143
|
```
|
|
306
144
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
---
|
|
145
|
+
`RouteView` is not available from `/legacy`. Use `useRouteNode` with a switch/case pattern instead.
|
|
310
146
|
|
|
311
147
|
## Migration from react-router5
|
|
312
148
|
|
|
313
|
-
| API
|
|
314
|
-
|
|
315
|
-
| `RouterProvider`
|
|
316
|
-
| `
|
|
317
|
-
| `
|
|
318
|
-
| `
|
|
319
|
-
| `
|
|
149
|
+
| API | react-router5 | @real-router/react |
|
|
150
|
+
|-----|---------------|-------------------|
|
|
151
|
+
| `RouterProvider`, `Link` | Yes | Yes |
|
|
152
|
+
| `useRouter`, `useRoute`, `useRouteNode` | Yes | Yes |
|
|
153
|
+
| `RouteView` with `keepAlive` | No | Yes (React 19.2+) |
|
|
154
|
+
| `useNavigator`, `useRouteUtils`, `useRouterTransition` | No | Yes |
|
|
155
|
+
| `withRouter`, `withRoute`, `routeNode` (HOCs) | Yes | No — use hooks |
|
|
156
|
+
| `Router`, `Route`, `RouteNode` (render props) | Yes | No — use hooks |
|
|
157
|
+
|
|
158
|
+
## Documentation
|
|
159
|
+
|
|
160
|
+
Full documentation: [Wiki](https://github.com/greydragon888/real-router/wiki)
|
|
320
161
|
|
|
321
|
-
|
|
162
|
+
- [RouterProvider](https://github.com/greydragon888/real-router/wiki/RouterProvider) · [RouteView](https://github.com/greydragon888/real-router/wiki/RouteView) · [Link](https://github.com/greydragon888/real-router/wiki/Link)
|
|
163
|
+
- [useRouter](https://github.com/greydragon888/real-router/wiki/useRouter) · [useRoute](https://github.com/greydragon888/real-router/wiki/useRoute) · [useRouteNode](https://github.com/greydragon888/real-router/wiki/useRouteNode) · [useNavigator](https://github.com/greydragon888/real-router/wiki/useNavigator) · [useRouteUtils](https://github.com/greydragon888/real-router/wiki/useRouteUtils) · [useRouterTransition](https://github.com/greydragon888/real-router/wiki/useRouterTransition)
|
|
322
164
|
|
|
323
165
|
## Related Packages
|
|
324
166
|
|
|
325
|
-
|
|
326
|
-
|
|
167
|
+
| Package | Description |
|
|
168
|
+
|---------|-------------|
|
|
169
|
+
| [@real-router/core](https://www.npmjs.com/package/@real-router/core) | Core router (required dependency) |
|
|
170
|
+
| [@real-router/browser-plugin](https://www.npmjs.com/package/@real-router/browser-plugin) | Browser History API integration |
|
|
171
|
+
| [@real-router/sources](https://www.npmjs.com/package/@real-router/sources) | Subscription layer (used internally) |
|
|
172
|
+
| [@real-router/route-utils](https://www.npmjs.com/package/@real-router/route-utils) | Route tree queries (`useRouteUtils`) |
|
|
173
|
+
|
|
174
|
+
## Contributing
|
|
175
|
+
|
|
176
|
+
See [contributing guidelines](../../CONTRIBUTING.md) for development setup and PR process.
|
|
327
177
|
|
|
328
178
|
## License
|
|
329
179
|
|
|
330
|
-
MIT © [Oleg Ivanov](https://github.com/greydragon888)
|
|
180
|
+
[MIT](../../LICENSE) © [Oleg Ivanov](https://github.com/greydragon888)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@real-router/react",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.3",
|
|
4
4
|
"type": "commonjs",
|
|
5
5
|
"description": "React integration for Real-Router",
|
|
6
6
|
"main": "./dist/cjs/index.js",
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
"license": "MIT",
|
|
65
65
|
"sideEffects": false,
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@real-router/core": "^0.
|
|
68
|
-
"@real-router/
|
|
69
|
-
"@real-router/
|
|
67
|
+
"@real-router/core": "^0.37.0",
|
|
68
|
+
"@real-router/route-utils": "^0.1.5",
|
|
69
|
+
"@real-router/sources": "^0.2.4"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@testing-library/dom": "10.4.1",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@testing-library/react": "16.3.2",
|
|
75
75
|
"@testing-library/user-event": "14.6.1",
|
|
76
76
|
"vitest-react-profiler": "1.12.0",
|
|
77
|
-
"@real-router/browser-plugin": "^0.10.
|
|
77
|
+
"@real-router/browser-plugin": "^0.10.2"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"@types/react": ">=18.0.0",
|