@solidjs/router 0.15.3 → 0.16.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.
- package/README.md +178 -141
- package/dist/data/action.d.ts +1 -1
- package/dist/data/createAsync.js +8 -6
- package/dist/data/query.js +11 -5
- package/dist/data/response.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +57 -22
- package/dist/routers/HashRouter.d.ts +1 -1
- package/dist/routers/Router.js +1 -1
- package/dist/routers/components.d.ts +1 -1
- package/dist/routers/components.jsx +5 -2
- package/dist/routers/createRouter.d.ts +1 -1
- package/dist/src/components.d.ts +31 -0
- package/dist/src/components.jsx +39 -0
- package/dist/src/data/action.d.ts +17 -0
- package/dist/src/data/action.js +163 -0
- package/dist/src/data/action.spec.d.ts +1 -0
- package/dist/src/data/action.spec.js +297 -0
- package/dist/src/data/createAsync.d.ts +32 -0
- package/dist/src/data/createAsync.js +96 -0
- package/dist/src/data/createAsync.spec.d.ts +1 -0
- package/dist/src/data/createAsync.spec.js +196 -0
- package/dist/src/data/events.d.ts +9 -0
- package/dist/src/data/events.js +123 -0
- package/dist/src/data/events.spec.d.ts +1 -0
- package/dist/src/data/events.spec.js +567 -0
- package/dist/src/data/index.d.ts +4 -0
- package/dist/src/data/index.js +4 -0
- package/dist/src/data/query.d.ts +23 -0
- package/dist/src/data/query.js +232 -0
- package/dist/src/data/query.spec.d.ts +1 -0
- package/dist/src/data/query.spec.js +354 -0
- package/dist/src/data/response.d.ts +4 -0
- package/dist/src/data/response.js +42 -0
- package/dist/src/data/response.spec.d.ts +1 -0
- package/dist/src/data/response.spec.js +165 -0
- package/dist/src/index.d.ts +7 -0
- package/dist/src/index.jsx +6 -0
- package/dist/src/lifecycle.d.ts +5 -0
- package/dist/src/lifecycle.js +69 -0
- package/dist/src/routers/HashRouter.d.ts +9 -0
- package/dist/src/routers/HashRouter.js +41 -0
- package/dist/src/routers/MemoryRouter.d.ts +24 -0
- package/dist/src/routers/MemoryRouter.js +57 -0
- package/dist/src/routers/Router.d.ts +9 -0
- package/dist/src/routers/Router.js +45 -0
- package/dist/src/routers/StaticRouter.d.ts +6 -0
- package/dist/src/routers/StaticRouter.js +15 -0
- package/dist/src/routers/components.d.ts +27 -0
- package/dist/src/routers/components.jsx +118 -0
- package/dist/src/routers/createRouter.d.ts +10 -0
- package/dist/src/routers/createRouter.js +41 -0
- package/dist/src/routers/index.d.ts +11 -0
- package/dist/src/routers/index.js +6 -0
- package/dist/src/routing.d.ts +175 -0
- package/dist/src/routing.js +560 -0
- package/dist/src/types.d.ts +200 -0
- package/dist/src/types.js +1 -0
- package/dist/src/utils.d.ts +13 -0
- package/dist/src/utils.js +185 -0
- package/dist/test/helpers.d.ts +6 -0
- package/dist/test/helpers.js +50 -0
- package/dist/types.d.ts +2 -2
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +3 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -1,16 +1,34 @@
|
|
|
1
|
-
|
|
2
|
-
<img src="https://assets.solidjs.com/banner?project=Router&type=core" alt="Solid Router" />
|
|
3
|
-
</p>
|
|
1
|
+
[](https://github.com/solidjs)
|
|
4
2
|
|
|
5
|
-
|
|
3
|
+
<div align="center">
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
[](https://npmjs.com/package/@solidjs/router)
|
|
6
|
+
[](https://npmjs.com/package/@solidjs/router)
|
|
7
|
+
[](https://github.com/solidjs/solid-router)
|
|
8
|
+
[](https://discord.com/invite/solidjs)
|
|
9
|
+
[](https://reddit.com/r/solidjs)
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
</div>
|
|
10
12
|
|
|
11
|
-
Solid Router
|
|
13
|
+
**Solid Router** brings fine-grained reactivity to route navigation, enabling your single-page application to become multi-paged without full page reloads. Fully integrated into the SolidJS ecosystem, Solid Router provides declarative syntax with features like universal rendering and parallel data fetching for best performance.
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
Explore the official [documentation](https://docs.solidjs.com/solid-router) for detailed guides and examples.
|
|
16
|
+
|
|
17
|
+
## Core Features
|
|
18
|
+
|
|
19
|
+
- **All Routing Modes**:
|
|
20
|
+
- [History-Based](https://docs.solidjs.com/solid-router/reference/components/router#router) for standard browser navigation
|
|
21
|
+
- [Hash-Based](https://docs.solidjs.com/solid-router/reference/components/hash-router#hashrouter) for navigation based on URL hash
|
|
22
|
+
- [Static Routing](https://docs.solidjs.com/solid-router/rendering-modes/ssr#server-side-rendering) for server-side rendering (_SSR_)
|
|
23
|
+
- [Memory-Based](https://docs.solidjs.com/solid-router/reference/components/memory-router#memoryrouter) for testing in non-browser environments
|
|
24
|
+
- **TypeScript**: Full integration for robust, type-safe development
|
|
25
|
+
- **Universal Rendering**: Seamless rendering on both client and server environments
|
|
26
|
+
- **Declarative**: Define routes as components or as an object
|
|
27
|
+
- **Preload Functions**: Parallel data fetching, following the render-as-you-fetch pattern
|
|
28
|
+
- **Dynamic Route Parameters**: Flexible URL patterns with parameters, optional segments, and wildcards
|
|
29
|
+
- **Data APIs with Caching**: Reactive data fetching with deduplication and revalidation
|
|
30
|
+
|
|
31
|
+
## Table of contents
|
|
14
32
|
|
|
15
33
|
- [Getting Started](#getting-started)
|
|
16
34
|
- [Set Up the Router](#set-up-the-router)
|
|
@@ -38,8 +56,9 @@ It supports all of Solid's SSR methods and has Solid's transitions baked in, so
|
|
|
38
56
|
|
|
39
57
|
### Set Up the Router
|
|
40
58
|
|
|
41
|
-
```
|
|
42
|
-
|
|
59
|
+
```bash
|
|
60
|
+
# use preferred package manager
|
|
61
|
+
npm add @solidjs/router
|
|
43
62
|
```
|
|
44
63
|
|
|
45
64
|
Install `@solidjs/router`, then start your application by rendering the router component
|
|
@@ -48,10 +67,7 @@ Install `@solidjs/router`, then start your application by rendering the router c
|
|
|
48
67
|
import { render } from "solid-js/web";
|
|
49
68
|
import { Router } from "@solidjs/router";
|
|
50
69
|
|
|
51
|
-
render(
|
|
52
|
-
() => <Router />,
|
|
53
|
-
document.getElementById("app")
|
|
54
|
-
);
|
|
70
|
+
render(() => <Router />, document.getElementById("app"));
|
|
55
71
|
```
|
|
56
72
|
|
|
57
73
|
This sets up a Router that will match on the url to display the desired page
|
|
@@ -69,13 +85,17 @@ import { Router, Route } from "@solidjs/router";
|
|
|
69
85
|
import Home from "./pages/Home";
|
|
70
86
|
import Users from "./pages/Users";
|
|
71
87
|
|
|
72
|
-
render(
|
|
73
|
-
|
|
74
|
-
<
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
88
|
+
render(
|
|
89
|
+
() => (
|
|
90
|
+
<Router>
|
|
91
|
+
<Route path="/users" component={Users} />
|
|
92
|
+
<Route path="/" component={Home} />
|
|
93
|
+
</Router>
|
|
94
|
+
),
|
|
95
|
+
document.getElementById("app")
|
|
96
|
+
);
|
|
78
97
|
```
|
|
98
|
+
|
|
79
99
|
2. Provide a root level layout
|
|
80
100
|
|
|
81
101
|
This will always be there and won't update on page change. It is the ideal place to put top level navigation and Context Providers
|
|
@@ -87,24 +107,27 @@ import { Router, Route } from "@solidjs/router";
|
|
|
87
107
|
import Home from "./pages/Home";
|
|
88
108
|
import Users from "./pages/Users";
|
|
89
109
|
|
|
90
|
-
const App = props => (
|
|
110
|
+
const App = (props) => (
|
|
91
111
|
<>
|
|
92
112
|
<h1>My Site with lots of pages</h1>
|
|
93
113
|
{props.children}
|
|
94
114
|
</>
|
|
95
|
-
)
|
|
115
|
+
);
|
|
96
116
|
|
|
97
|
-
render(
|
|
98
|
-
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
117
|
+
render(
|
|
118
|
+
() => (
|
|
119
|
+
<Router root={App}>
|
|
120
|
+
<Route path="/users" component={Users} />
|
|
121
|
+
<Route path="/" component={Home} />
|
|
122
|
+
</Router>
|
|
123
|
+
),
|
|
124
|
+
document.getElementById("app")
|
|
125
|
+
);
|
|
103
126
|
```
|
|
104
127
|
|
|
105
|
-
3. Create a
|
|
128
|
+
3. Create a catch-all route (404 page)
|
|
106
129
|
|
|
107
|
-
We can create
|
|
130
|
+
We can create catch-all routes for pages not found at any nested level of the router. We use `*` and optionally the name of a parameter to retrieve the rest of the path.
|
|
108
131
|
|
|
109
132
|
```jsx
|
|
110
133
|
import { render } from "solid-js/web";
|
|
@@ -114,20 +137,23 @@ import Home from "./pages/Home";
|
|
|
114
137
|
import Users from "./pages/Users";
|
|
115
138
|
import NotFound from "./pages/404";
|
|
116
139
|
|
|
117
|
-
const App = props => (
|
|
140
|
+
const App = (props) => (
|
|
118
141
|
<>
|
|
119
142
|
<h1>My Site with lots of pages</h1>
|
|
120
143
|
{props.children}
|
|
121
144
|
</>
|
|
122
|
-
)
|
|
145
|
+
);
|
|
123
146
|
|
|
124
|
-
render(
|
|
125
|
-
|
|
126
|
-
<
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
147
|
+
render(
|
|
148
|
+
() => (
|
|
149
|
+
<Router root={App}>
|
|
150
|
+
<Route path="/users" component={Users} />
|
|
151
|
+
<Route path="/" component={Home} />
|
|
152
|
+
<Route path="*404" component={NotFound} />
|
|
153
|
+
</Router>
|
|
154
|
+
),
|
|
155
|
+
document.getElementById("app")
|
|
156
|
+
);
|
|
131
157
|
```
|
|
132
158
|
|
|
133
159
|
4. Lazy-load route components
|
|
@@ -142,19 +168,22 @@ import { Router, Route } from "@solidjs/router";
|
|
|
142
168
|
const Users = lazy(() => import("./pages/Users"));
|
|
143
169
|
const Home = lazy(() => import("./pages/Home"));
|
|
144
170
|
|
|
145
|
-
const App = props => (
|
|
171
|
+
const App = (props) => (
|
|
146
172
|
<>
|
|
147
173
|
<h1>My Site with lots of pages</h1>
|
|
148
174
|
{props.children}
|
|
149
175
|
</>
|
|
150
|
-
)
|
|
176
|
+
);
|
|
151
177
|
|
|
152
|
-
render(
|
|
153
|
-
|
|
154
|
-
<
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
178
|
+
render(
|
|
179
|
+
() => (
|
|
180
|
+
<Router root={App}>
|
|
181
|
+
<Route path="/users" component={Users} />
|
|
182
|
+
<Route path="/" component={Home} />
|
|
183
|
+
</Router>
|
|
184
|
+
),
|
|
185
|
+
document.getElementById("app")
|
|
186
|
+
);
|
|
158
187
|
```
|
|
159
188
|
|
|
160
189
|
### Create Links to Your Routes
|
|
@@ -169,7 +198,7 @@ import { Router, Route } from "@solidjs/router";
|
|
|
169
198
|
const Users = lazy(() => import("./pages/Users"));
|
|
170
199
|
const Home = lazy(() => import("./pages/Home"));
|
|
171
200
|
|
|
172
|
-
const App = props => (
|
|
201
|
+
const App = (props) => (
|
|
173
202
|
<>
|
|
174
203
|
<nav>
|
|
175
204
|
<a href="/about">About</a>
|
|
@@ -180,12 +209,15 @@ const App = props => (
|
|
|
180
209
|
</>
|
|
181
210
|
);
|
|
182
211
|
|
|
183
|
-
render(
|
|
184
|
-
|
|
185
|
-
<
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
212
|
+
render(
|
|
213
|
+
() => (
|
|
214
|
+
<Router root={App}>
|
|
215
|
+
<Route path="/users" component={Users} />
|
|
216
|
+
<Route path="/" component={Home} />
|
|
217
|
+
</Router>
|
|
218
|
+
),
|
|
219
|
+
document.getElementById("app")
|
|
220
|
+
);
|
|
189
221
|
```
|
|
190
222
|
|
|
191
223
|
## Dynamic Routes
|
|
@@ -201,13 +233,16 @@ const Users = lazy(() => import("./pages/Users"));
|
|
|
201
233
|
const User = lazy(() => import("./pages/User"));
|
|
202
234
|
const Home = lazy(() => import("./pages/Home"));
|
|
203
235
|
|
|
204
|
-
render(
|
|
205
|
-
|
|
206
|
-
<
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
236
|
+
render(
|
|
237
|
+
() => (
|
|
238
|
+
<Router>
|
|
239
|
+
<Route path="/users" component={Users} />
|
|
240
|
+
<Route path="/users/:id" component={User} />
|
|
241
|
+
<Route path="/" component={Home} />
|
|
242
|
+
</Router>
|
|
243
|
+
),
|
|
244
|
+
document.getElementById("app")
|
|
245
|
+
);
|
|
211
246
|
```
|
|
212
247
|
|
|
213
248
|
The colon indicates that `id` can be any string, and as long as the URL fits that pattern, the `User` component will show.
|
|
@@ -216,9 +251,13 @@ You can then access that `id` from within a route component with `useParams`.
|
|
|
216
251
|
|
|
217
252
|
**Note on Animation/Transitions**:
|
|
218
253
|
Routes that share the same path match will be treated as the same route. If you want to force re-render you can wrap your component in a keyed `<Show>` like:
|
|
254
|
+
|
|
219
255
|
```jsx
|
|
220
|
-
<Show when={params.something} keyed
|
|
256
|
+
<Show when={params.something} keyed>
|
|
257
|
+
<MyComponent />
|
|
258
|
+
</Show>
|
|
221
259
|
```
|
|
260
|
+
|
|
222
261
|
---
|
|
223
262
|
|
|
224
263
|
Each path parameter can be validated using a `MatchFilter`.
|
|
@@ -228,7 +267,7 @@ This allows for more complex routing descriptions than just checking the presenc
|
|
|
228
267
|
import { lazy } from "solid-js";
|
|
229
268
|
import { render } from "solid-js/web";
|
|
230
269
|
import { Router, Route } from "@solidjs/router";
|
|
231
|
-
import type {
|
|
270
|
+
import type { MatchFilters } from "@solidjs/router";
|
|
232
271
|
|
|
233
272
|
const User = lazy(() => import("./pages/User"));
|
|
234
273
|
|
|
@@ -238,15 +277,18 @@ const filters: MatchFilters = {
|
|
|
238
277
|
withHtmlExtension: (v: string) => v.length > 5 && v.endsWith(".html"), // we want an `*.html` extension
|
|
239
278
|
};
|
|
240
279
|
|
|
241
|
-
render(
|
|
242
|
-
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
280
|
+
render(
|
|
281
|
+
() => (
|
|
282
|
+
<Router>
|
|
283
|
+
<Route
|
|
284
|
+
path="/users/:parent/:id/:withHtmlExtension"
|
|
285
|
+
component={User}
|
|
286
|
+
matchFilters={filters}
|
|
287
|
+
/>
|
|
288
|
+
</Router>
|
|
289
|
+
),
|
|
290
|
+
document.getElementById("app")
|
|
291
|
+
);
|
|
250
292
|
```
|
|
251
293
|
|
|
252
294
|
Here, we have added the `matchFilters` prop. This allows us to validate the `parent`, `id` and `withHtmlExtension` parameters against the filters defined in `filters`.
|
|
@@ -358,24 +400,13 @@ You can nest indefinitely - just remember that only leaf nodes will become their
|
|
|
358
400
|
```jsx
|
|
359
401
|
<Route
|
|
360
402
|
path="/"
|
|
361
|
-
component={(props) =>
|
|
362
|
-
<div>
|
|
363
|
-
Onion starts here {props.children}
|
|
364
|
-
</div>
|
|
365
|
-
}
|
|
403
|
+
component={(props) => <div>Onion starts here {props.children}</div>}
|
|
366
404
|
>
|
|
367
405
|
<Route
|
|
368
406
|
path="layer1"
|
|
369
|
-
component={(props) =>
|
|
370
|
-
<div>
|
|
371
|
-
Another layer {props.children}
|
|
372
|
-
</div>
|
|
373
|
-
}
|
|
407
|
+
component={(props) => <div>Another layer {props.children}</div>}
|
|
374
408
|
>
|
|
375
|
-
<Route
|
|
376
|
-
path="layer2"
|
|
377
|
-
component={() => <div>Innermost layer</div>}
|
|
378
|
-
/>
|
|
409
|
+
<Route path="layer2" component={() => <div>Innermost layer</div>} />
|
|
379
410
|
</Route>
|
|
380
411
|
</Route>
|
|
381
412
|
```
|
|
@@ -393,7 +424,7 @@ import { Route } from "@solidjs/router";
|
|
|
393
424
|
const User = lazy(() => import("./pages/users/[id].js"));
|
|
394
425
|
|
|
395
426
|
// preload function
|
|
396
|
-
function preloadUser({params, location}) {
|
|
427
|
+
function preloadUser({ params, location }) {
|
|
397
428
|
// do preloading
|
|
398
429
|
}
|
|
399
430
|
|
|
@@ -401,12 +432,11 @@ function preloadUser({params, location}) {
|
|
|
401
432
|
<Route path="/users/:id" component={User} preload={preloadUser} />;
|
|
402
433
|
```
|
|
403
434
|
|
|
404
|
-
| key | type
|
|
405
|
-
| -------- |
|
|
406
|
-
| params | object
|
|
407
|
-
| location | `{ pathname, search, hash, query, state, key}`
|
|
408
|
-
| intent
|
|
409
|
-
|
|
435
|
+
| key | type | description |
|
|
436
|
+
| -------- | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
437
|
+
| params | object | The route parameters (same value as calling `useParams()` inside the route component) |
|
|
438
|
+
| location | `{ pathname, search, hash, query, state, key}` | An object that you can use to get more information about the path (corresponds to [`useLocation()`](#uselocation)) |
|
|
439
|
+
| intent | `"initial", "navigate", "native", "preload"` | Indicates why this function is being called. <ul><li>"initial" - the route is being initially shown (ie page load)</li><li>"native" - navigate originated from the browser (eg back/forward)</li><li>"navigate" - navigate originated from the router (eg call to navigate or anchor clicked)</li><li>"preload" - not navigating, just preloading (eg link hover)</li></ul> |
|
|
410
440
|
|
|
411
441
|
A common pattern is to export the preload function and data wrappers that corresponds to a route in a dedicated `route.data.js` file. This way, the data function can be imported without loading anything else.
|
|
412
442
|
|
|
@@ -420,22 +450,22 @@ const User = lazy(() => import("/pages/users/[id].js"));
|
|
|
420
450
|
<Route path="/users/:id" component={User} preload={preloadUser} />;
|
|
421
451
|
```
|
|
422
452
|
|
|
423
|
-
The
|
|
424
|
-
|
|
453
|
+
The `preload` function's return value is passed to the page component for any intent other than `"preload"`, allowing you to initialize data or alternatively use our new Data APIs:
|
|
425
454
|
|
|
426
455
|
## Data APIs
|
|
427
456
|
|
|
428
|
-
Keep in mind these are
|
|
457
|
+
Keep in mind that these are entirely optional, but they demonstrate the power of our preload mechanism.
|
|
429
458
|
|
|
430
459
|
### `query`
|
|
431
460
|
|
|
432
|
-
To prevent duplicate fetching and to
|
|
461
|
+
To prevent duplicate fetching and to handle refetching triggers, we provide a query API that accepts a function and returns the same function.
|
|
433
462
|
|
|
434
463
|
```jsx
|
|
435
464
|
const getUser = query(async (id) => {
|
|
436
|
-
return (await fetch(`/api/users
|
|
437
|
-
}, "users") // used as the query key + serialized arguments
|
|
465
|
+
return (await fetch(`/api/users/${id}`)).json();
|
|
466
|
+
}, "users"); // used as the query key + serialized arguments
|
|
438
467
|
```
|
|
468
|
+
|
|
439
469
|
It is expected that the arguments to the query function are serializable.
|
|
440
470
|
|
|
441
471
|
This query accomplishes the following:
|
|
@@ -476,11 +506,12 @@ export default function User(props) {
|
|
|
476
506
|
```
|
|
477
507
|
|
|
478
508
|
Cached function has a few useful methods for getting the key that are useful for invalidation.
|
|
509
|
+
|
|
479
510
|
```ts
|
|
480
511
|
let id = 5;
|
|
481
512
|
|
|
482
|
-
getUser.key // returns "users"
|
|
483
|
-
getUser.keyFor(id) // returns "users[5]"
|
|
513
|
+
getUser.key; // returns "users"
|
|
514
|
+
getUser.keyFor(id); // returns "users[5]"
|
|
484
515
|
```
|
|
485
516
|
|
|
486
517
|
You can revalidate the query using the `revalidate` method or you can set `revalidate` keys on your response from your actions. If you pass the whole key it will invalidate all the entries for the query (ie "users" in the example above). You can also invalidate a single entry by using `keyFor`.
|
|
@@ -492,13 +523,13 @@ You can revalidate the query using the `revalidate` method or you can set `reval
|
|
|
492
523
|
This is light wrapper over `createResource` that aims to serve as stand-in for a future primitive we intend to bring to Solid core in 2.0. It is a simpler async primitive where the function tracks like `createMemo` and it expects a promise back that it turns into a Signal. Reading it before it is ready causes Suspense/Transitions to trigger.
|
|
493
524
|
|
|
494
525
|
```jsx
|
|
495
|
-
const user = createAsync((currentValue) => getUser(params.id))
|
|
526
|
+
const user = createAsync((currentValue) => getUser(params.id));
|
|
496
527
|
```
|
|
497
528
|
|
|
498
529
|
It also preserves `latest` field from `createResource`. Note that it will be removed in the future.
|
|
499
530
|
|
|
500
531
|
```jsx
|
|
501
|
-
const user = createAsync((currentValue) => getUser(params.id))
|
|
532
|
+
const user = createAsync((currentValue) => getUser(params.id));
|
|
502
533
|
return <h1>{user.latest.name}</h1>;
|
|
503
534
|
```
|
|
504
535
|
|
|
@@ -516,6 +547,7 @@ const todos = createAsyncStore(() => getTodos());
|
|
|
516
547
|
### `action`
|
|
517
548
|
|
|
518
549
|
Actions are data mutations that can trigger invalidations and further routing. A list of prebuilt response helpers can be found below.
|
|
550
|
+
|
|
519
551
|
```jsx
|
|
520
552
|
import { action, revalidate, redirect } from "@solidjs/router"
|
|
521
553
|
|
|
@@ -549,18 +581,21 @@ const deleteTodo = action(async (formData: FormData) => {
|
|
|
549
581
|
<button type="submit">Delete</button>
|
|
550
582
|
</form>
|
|
551
583
|
```
|
|
584
|
+
|
|
552
585
|
Instead with `with` you can write this:
|
|
586
|
+
|
|
553
587
|
```js
|
|
554
|
-
const
|
|
588
|
+
const deleteTodo = action(api.deleteTodo)
|
|
555
589
|
|
|
556
590
|
<form action={deleteTodo.with(todo.id)} method="post">
|
|
557
591
|
<button type="submit">Delete</button>
|
|
558
592
|
</form>
|
|
559
593
|
```
|
|
560
594
|
|
|
561
|
-
Actions also a second argument which can be the name or an option object with `name` and `onComplete`. `name` is used to identify SSR actions that aren't server functions (see note below). `onComplete` allows you to configure behavior when `action`s complete. Keep in mind `onComplete` does not work when JavaScript is disabled.
|
|
595
|
+
Actions also take a second argument which can be the name or an option object with `name` and `onComplete`. `name` is used to identify SSR actions that aren't server functions (see note below). `onComplete` allows you to configure behavior when `action`s complete. Keep in mind `onComplete` does not work when JavaScript is disabled.
|
|
562
596
|
|
|
563
597
|
#### Notes on `<form>` implementation and SSR
|
|
598
|
+
|
|
564
599
|
This requires stable references as you can only serialize a string as an attribute, and across SSR they'd need to match. The solution is providing a unique name.
|
|
565
600
|
|
|
566
601
|
```jsx
|
|
@@ -573,11 +608,11 @@ Instead of forms you can use actions directly by wrapping them in a `useAction`
|
|
|
573
608
|
|
|
574
609
|
```jsx
|
|
575
610
|
// in component
|
|
576
|
-
const submit = useAction(myAction)
|
|
577
|
-
submit(...args)
|
|
611
|
+
const submit = useAction(myAction);
|
|
612
|
+
submit(...args);
|
|
578
613
|
```
|
|
579
614
|
|
|
580
|
-
The outside of a form context you can use custom data instead of formData, and these helpers preserve types. However, even when used with server functions (in projects like SolidStart) this requires client side javascript and is not Progressive
|
|
615
|
+
The outside of a form context you can use custom data instead of formData, and these helpers preserve types. However, even when used with server functions (in projects like SolidStart) this requires client side javascript and is not Progressive Enhanceable like forms are.
|
|
581
616
|
|
|
582
617
|
### `useSubmission`/`useSubmissions`
|
|
583
618
|
|
|
@@ -604,6 +639,7 @@ These are used to communicate router navigations from query/actions, and can inc
|
|
|
604
639
|
#### `redirect(path, options)`
|
|
605
640
|
|
|
606
641
|
Redirects to the next route
|
|
642
|
+
|
|
607
643
|
```js
|
|
608
644
|
const getUser = query(() => {
|
|
609
645
|
const user = await api.getCurrentUser()
|
|
@@ -615,16 +651,17 @@ const getUser = query(() => {
|
|
|
615
651
|
#### `reload(options)`
|
|
616
652
|
|
|
617
653
|
Reloads the data on the current page
|
|
654
|
+
|
|
618
655
|
```js
|
|
619
656
|
const getTodo = query(async (id: number) => {
|
|
620
657
|
const todo = await fetchTodo(id);
|
|
621
658
|
return todo;
|
|
622
|
-
}, "todo")
|
|
659
|
+
}, "todo");
|
|
623
660
|
|
|
624
661
|
const updateTodo = action(async (todo: Todo) => {
|
|
625
662
|
await updateTodo(todo.id, todo);
|
|
626
|
-
reload({ revalidate: getTodo.keyFor(id) })
|
|
627
|
-
})
|
|
663
|
+
reload({ revalidate: getTodo.keyFor(todo.id) });
|
|
664
|
+
});
|
|
628
665
|
```
|
|
629
666
|
|
|
630
667
|
## Config Based Routing
|
|
@@ -669,10 +706,7 @@ const routes = [
|
|
|
669
706
|
},
|
|
670
707
|
];
|
|
671
708
|
|
|
672
|
-
render(() =>
|
|
673
|
-
<Router>{routes}</Router>,
|
|
674
|
-
document.getElementById("app")
|
|
675
|
-
);
|
|
709
|
+
render(() => <Router>{routes}</Router>, document.getElementById("app"));
|
|
676
710
|
```
|
|
677
711
|
|
|
678
712
|
Also you can pass a single route definition object for a single route:
|
|
@@ -684,7 +718,7 @@ import { Router } from "@solidjs/router";
|
|
|
684
718
|
|
|
685
719
|
const route = {
|
|
686
720
|
path: "/",
|
|
687
|
-
component: lazy(() => import("/pages/index.js"))
|
|
721
|
+
component: lazy(() => import("/pages/index.js")),
|
|
688
722
|
};
|
|
689
723
|
|
|
690
724
|
render(() => <Router>{route}</Router>, document.getElementById("app"));
|
|
@@ -723,29 +757,28 @@ import { Router } from "@solidjs/router";
|
|
|
723
757
|
<Router url={isServer ? req.url : ""} />;
|
|
724
758
|
```
|
|
725
759
|
|
|
726
|
-
|
|
727
760
|
## Components
|
|
728
761
|
|
|
729
762
|
### `<Router>`
|
|
730
763
|
|
|
731
764
|
This is the main Router component for the browser.
|
|
732
765
|
|
|
733
|
-
| prop
|
|
734
|
-
|
|
735
|
-
| children
|
|
736
|
-
| root
|
|
737
|
-
| base
|
|
738
|
-
| actionBase
|
|
739
|
-
| preload
|
|
740
|
-
| explicitLinks | boolean
|
|
766
|
+
| prop | type | description |
|
|
767
|
+
| ------------- | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
768
|
+
| children | `JSX.Element`, `RouteDefinition`, or `RouteDefinition[]` | The route definitions |
|
|
769
|
+
| root | Component | Top level layout component |
|
|
770
|
+
| base | string | Base url to use for matching routes |
|
|
771
|
+
| actionBase | string | Root url for server actions, default: `/_server` |
|
|
772
|
+
| preload | boolean | Enables/disables preloads globally, default: `true` |
|
|
773
|
+
| explicitLinks | boolean | Disables all anchors being intercepted and instead requires `<A>`. Default: `false`. (To disable interception for a specific link, set `target` to any value, e.g. `<a target="_self">`.) |
|
|
741
774
|
|
|
742
775
|
### `<A>`
|
|
743
776
|
|
|
744
777
|
Like the `<a>` tag but supports automatic apply of base path + relative paths and active class styling (requires client side JavaScript).
|
|
745
778
|
|
|
746
|
-
The `<A>` tag has an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are
|
|
779
|
+
The `<A>` tag has an `active` class if its href matches the current location, and `inactive` otherwise. **Note:** By default matching includes locations that are descendants (eg. href `/users` matches locations `/users` and `/users/123`), use the boolean `end` prop to prevent matching these. This is particularly useful for links to the root route `/` which would match everything.
|
|
747
780
|
|
|
748
|
-
| prop |
|
|
781
|
+
| prop | type | description |
|
|
749
782
|
| ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
750
783
|
| href | string | The path of the route to navigate to. This will be resolved relative to the route that the link is in, but you can preface it with `/` to refer back to the root. |
|
|
751
784
|
| noScroll | boolean | If true, turn off the default behavior of scrolling to the top of the new page |
|
|
@@ -753,7 +786,7 @@ The `<A>` tag has an `active` class if its href matches the current location, an
|
|
|
753
786
|
| state | unknown | [Push this value](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState) to the history stack when navigating |
|
|
754
787
|
| inactiveClass | string | The class to show when the link is inactive (when the current location doesn't match the link) |
|
|
755
788
|
| activeClass | string | The class to show when the link is active |
|
|
756
|
-
| end | boolean | If `true`, only considers the link to be active when the
|
|
789
|
+
| end | boolean | If `true`, only considers the link to be active when the current location matches the `href` exactly; if `false`, check if the current location _starts with_ `href` |
|
|
757
790
|
|
|
758
791
|
### `<Navigate />`
|
|
759
792
|
|
|
@@ -774,13 +807,13 @@ function getPath({ navigate, location }) {
|
|
|
774
807
|
|
|
775
808
|
The Component for defining Routes:
|
|
776
809
|
|
|
777
|
-
| prop
|
|
778
|
-
|
|
779
|
-
| path
|
|
780
|
-
| component
|
|
781
|
-
| matchFilters | `MatchFilters`
|
|
782
|
-
| children
|
|
783
|
-
| preload
|
|
810
|
+
| prop | type | description |
|
|
811
|
+
| ------------ | ------------------ | ----------------------------------------------------------------- |
|
|
812
|
+
| path | string | Path partial for defining the route segment |
|
|
813
|
+
| component | `Component` | Component that will be rendered for the matched segment |
|
|
814
|
+
| matchFilters | `MatchFilters` | Additional constraints for matching against the route |
|
|
815
|
+
| children | `JSX.Element` | Nested `<Route>` definitions |
|
|
816
|
+
| preload | `RoutePreloadFunc` | Function called during preload or when the route is navigated to. |
|
|
784
817
|
|
|
785
818
|
## Router Primitives
|
|
786
819
|
|
|
@@ -878,10 +911,13 @@ return <div classList={{ active: Boolean(match()) }} />;
|
|
|
878
911
|
`useCurrentMatches` returns all the matches for the current matched route. Useful for getting all the route information.
|
|
879
912
|
|
|
880
913
|
For example if you stored breadcrumbs on your route definition you could retrieve them like so:
|
|
914
|
+
|
|
881
915
|
```js
|
|
882
916
|
const matches = useCurrentMatches();
|
|
883
917
|
|
|
884
|
-
const breadcrumbs = createMemo(() =>
|
|
918
|
+
const breadcrumbs = createMemo(() =>
|
|
919
|
+
matches().map((m) => m.route.info.breadcrumb)
|
|
920
|
+
);
|
|
885
921
|
```
|
|
886
922
|
|
|
887
923
|
### usePreloadRoute
|
|
@@ -940,7 +976,7 @@ Related without Outlet component it has to be passed in manually. At which point
|
|
|
940
976
|
|
|
941
977
|
### `data` functions & `useRouteData`
|
|
942
978
|
|
|
943
|
-
These have been replaced by a preload mechanism. This
|
|
979
|
+
These have been replaced by a preload mechanism. This allows link hover preloads (as the preload function can be run as much as wanted without worry about reactivity). It support deduping/query APIs which give more control over how things are cached. It also addresses TS issues with getting the right types in the Component without `typeof` checks.
|
|
944
980
|
|
|
945
981
|
That being said you can reproduce the old pattern largely by turning off preloads at the router level and then injecting your own Context:
|
|
946
982
|
|
|
@@ -951,7 +987,7 @@ import { Route } from "@solidjs/router";
|
|
|
951
987
|
const User = lazy(() => import("./pages/users/[id].js"));
|
|
952
988
|
|
|
953
989
|
// preload function
|
|
954
|
-
function preloadUser({params, location}) {
|
|
990
|
+
function preloadUser({ params, location }) {
|
|
955
991
|
const [user] = createResource(() => params.id, fetchUser);
|
|
956
992
|
return user;
|
|
957
993
|
}
|
|
@@ -959,20 +995,21 @@ function preloadUser({params, location}) {
|
|
|
959
995
|
// Pass it in the route definition
|
|
960
996
|
<Router preload={false}>
|
|
961
997
|
<Route path="/users/:id" component={User} preload={preloadUser} />
|
|
962
|
-
</Router
|
|
998
|
+
</Router>;
|
|
963
999
|
```
|
|
964
1000
|
|
|
965
1001
|
And then in your component taking the page props and putting them in a Context.
|
|
1002
|
+
|
|
966
1003
|
```js
|
|
967
1004
|
function User(props) {
|
|
968
1005
|
<UserContext.Provider value={props.data}>
|
|
969
1006
|
{/* my component content */}
|
|
970
|
-
</UserContext.Provider
|
|
1007
|
+
</UserContext.Provider>;
|
|
971
1008
|
}
|
|
972
1009
|
|
|
973
1010
|
// Somewhere else
|
|
974
1011
|
function UserDetails() {
|
|
975
|
-
const user = useContext(UserContext)
|
|
1012
|
+
const user = useContext(UserContext);
|
|
976
1013
|
// render stuff
|
|
977
1014
|
}
|
|
978
1015
|
```
|
package/dist/data/action.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JSX } from "solid-js";
|
|
2
2
|
import type { Submission, SubmissionStub, NarrowResponse } from "../types.js";
|
|
3
|
-
export type Action<T extends Array<any>, U, V = T> = (T extends [FormData] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<NarrowResponse<U>>) & {
|
|
3
|
+
export type Action<T extends Array<any>, U, V = T> = (T extends [FormData | URLSearchParams] | [] ? JSX.SerializableAttributeValue : unknown) & ((...vars: T) => Promise<NarrowResponse<U>>) & {
|
|
4
4
|
url: string;
|
|
5
5
|
with<A extends any[], B extends any[]>(this: (this: any, ...args: [...A, ...B]) => Promise<NarrowResponse<U>>, ...args: A): Action<B, U, V>;
|
|
6
6
|
};
|