@solidjs/router 0.10.1 → 0.10.2

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 CHANGED
@@ -350,8 +350,53 @@ You can nest indefinitely - just remember that only leaf nodes will become their
350
350
  </Route>
351
351
  ```
352
352
 
353
+ ## Load Functions
354
+
355
+ Even with smart caches it is possible that we have waterfalls both with view logic and with lazy loaded code. With load functions, we can instead start fetching the data parallel to loading the route, so we can use the data as soon as possible. The load function is called when the Route is loaded or eagerly when links are hovered.
356
+
357
+ As its only argument, the load function is passed an object that you can use to access route information:
358
+
359
+ ```js
360
+ import { lazy } from "solid-js";
361
+ import { Route } from "@solidjs/router";
362
+
363
+ const User = lazy(() => import("./pages/users/[id].js"));
364
+
365
+ // load function
366
+ function loadUser({params, location}) {
367
+ // do loading
368
+ }
369
+
370
+ // Pass it in the route definition
371
+ <Route path="/users/:id" component={User} load={loadUser} />;
372
+ ```
373
+
374
+ | key | type | description |
375
+ | -------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
376
+ | params | object | The route parameters (same value as calling `useParams()` inside the route component) |
377
+ | location | `{ pathname, search, hash, query, state, key}` | An object that you can use to get more information about the path (corresponds to [`useLocation()`](#uselocation)) |
378
+ | 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> |
379
+
380
+
381
+ A common pattern is to export the load 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.
382
+
383
+ ```js
384
+ import { lazy } from "solid-js";
385
+ import { Route } from "@solidjs/router";
386
+ import loadUser from "./pages/users/[id].data.js";
387
+ const User = lazy(() => import("/pages/users/[id].js"));
388
+
389
+ // In the Route definition
390
+ <Route path="/users/:id" component={User} load={loadUser} />;
391
+ ```
392
+
393
+ The return value of the `load` function is passed to the page component when called at anytime other than `"preload"`, so you can initialize things in there, or alternatively use our new Data APIs:
394
+
395
+
353
396
  ## Data APIs
354
397
 
398
+ Keep in mind these are completely optional. To use but showcase the power of our load mechanism.
399
+
355
400
  ### `cache`
356
401
 
357
402
  To prevent duplicate fetching and to trigger handle refetching we provide a cache api. That takes a function and returns the same function.
@@ -370,6 +415,36 @@ This cache accomplishes the following:
370
415
  3. We have a reactive refetch mechanism based on key. So we can tell routes that aren't new to retrigger on action revalidation.
371
416
  4. It will serve as a back/forward cache for browser navigation up to 5 mins. Any user based navigation or link click bypasses it. Revalidation or new fetch updates the cache.
372
417
 
418
+ Using it with load function might look like:
419
+
420
+ ```js
421
+ import { lazy } from "solid-js";
422
+ import { Route } from "@solidjs/router";
423
+ import { getUser } from ... // the cache function
424
+
425
+ const User = lazy(() => import("./pages/users/[id].js"));
426
+
427
+ // load function
428
+ function loadUser({params, location}) {
429
+ void getUser(params.id)
430
+ }
431
+
432
+ // Pass it in the route definition
433
+ <Route path="/users/:id" component={User} load={loadUser} />;
434
+ ```
435
+
436
+ Inside your page component you:
437
+
438
+ ```jsx
439
+ // pages/users/[id].js
440
+ import { getUser } from ... // the cache function
441
+
442
+ export default function User(props) {
443
+ const user = createAsync(() => getUser(props.params.id));
444
+ return <h1>{user().name}</h1>;
445
+ }
446
+ ```
447
+
373
448
  Cached function has a few useful methods for getting the key that are useful for invalidation.
374
449
  ```ts
375
450
  let id = 5;
@@ -423,16 +498,16 @@ const deleteTodo = action(async (formData: FormData) => {
423
498
  await api.deleteTodo(id)
424
499
  })
425
500
 
426
- <form action={deleteUser} method="post">
501
+ <form action={deleteTodo} method="post">
427
502
  <input type="hidden" name="id" value={todo.id} />
428
503
  <button type="submit">Delete</button>
429
504
  </form>
430
505
  ```
431
506
  Instead with `with` you can write this:
432
507
  ```js
433
- const deleteUser = action(api.deleteUser)
508
+ const deleteUser = action(api.deleteTodo)
434
509
 
435
- <form action={deleteUser.with(todo.id)} method="post">
510
+ <form action={deleteTodo.with(todo.id)} method="post">
436
511
  <button type="submit">Delete</button>
437
512
  </form>
438
513
  ```
@@ -504,59 +579,6 @@ const updateTodo = action(async (todo: Todo) => {
504
579
  })
505
580
  ```
506
581
 
507
- ### Load Functions
508
-
509
- Even with the cache API it is possible that we have waterfalls both with view logic and with lazy loaded code. With load functions, we can instead start fetching the data parallel to loading the route, so we can use the data as soon as possible.
510
-
511
- To do this, we can call our cache function in the load function.
512
-
513
- ```js
514
- import { lazy } from "solid-js";
515
- import { Route } from "@solidjs/router";
516
- import { getUser } from ... // the cache function
517
-
518
- const User = lazy(() => import("./pages/users/[id].js"));
519
-
520
- // load function
521
- function loadUser({params, location}) {
522
- void getUser(params.id)
523
- }
524
-
525
- // Pass it in the route definition
526
- <Route path="/users/:id" component={User} load={loadUser} />;
527
- ```
528
-
529
- The load function is called when the Route is loaded or eagerly when links are hovered. Inside your page component you:
530
-
531
- ```jsx
532
- // pages/users/[id].js
533
- import { getUser } from ... // the cache function
534
-
535
- export default function User(props) {
536
- const user = createAsync(() => getUser(props.params.id));
537
- return <h1>{user().name}</h1>;
538
- }
539
- ```
540
-
541
- As its only argument, the load function is passed an object that you can use to access route information:
542
-
543
- | key | type | description |
544
- | -------- | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
545
- | params | object | The route parameters (same value as calling `useParams()` inside the route component) |
546
- | location | `{ pathname, search, hash, query, state, key}` | An object that you can use to get more information about the path (corresponds to [`useLocation()`](#uselocation)) |
547
-
548
- 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.
549
-
550
- ```js
551
- import { lazy } from "solid-js";
552
- import { Route } from "@solidjs/router";
553
- import loadUser from "./pages/users/[id].data.js";
554
- const User = lazy(() => import("/pages/users/[id].js"));
555
-
556
- // In the Route definition
557
- <Route path="/users/:id" component={User} load={loadUser} />;
558
- ```
559
-
560
582
  ## Config Based Routing
561
583
 
562
584
  You don't have to use JSX to set up your routes; you can pass an object:
@@ -834,6 +856,41 @@ Related without Outlet component it has to be passed in manually. At which point
834
856
 
835
857
  These have been replaced by a load mechanism. This allows link hover preloads (as the load function can be run as much as wanted without worry about reactivity). It support deduping/cache 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.
836
858
 
859
+ That being said you can reproduce the old pattern largely by turning off preloads at the router level and then injecting your own Context:
860
+
861
+ ```js
862
+ import { lazy } from "solid-js";
863
+ import { Route } from "@solidjs/router";
864
+
865
+ const User = lazy(() => import("./pages/users/[id].js"));
866
+
867
+ // load function
868
+ function loadUser({params, location}) {
869
+ const [user] = createResource(() => params.id, fetchUser);
870
+ return user;
871
+ }
872
+
873
+ // Pass it in the route definition
874
+ <Router preload={false}>
875
+ <Route path="/users/:id" component={User} load={loadUser} />
876
+ </Router>
877
+ ```
878
+
879
+ And then in your component taking the page props and putting them in a Context.
880
+ ```js
881
+ function User(props) {
882
+ <UserContext.Provider value={props.data}>
883
+ {/* my component content */}
884
+ </UserContext.Provider>
885
+ }
886
+
887
+ // Somewhere else
888
+ function UserDetails() {
889
+ const user = useContext(UserContext)
890
+ // render stuff
891
+ }
892
+ ```
893
+
837
894
  ## SPAs in Deployed Environments
838
895
 
839
896
  When deploying applications that use a client side router that does not rely on Server Side Rendering you need to handle redirects to your index page so that loading from other URLs does not cause your CDN or Hosting to return not found for pages that aren't actually there.
package/dist/index.js CHANGED
@@ -559,6 +559,12 @@ function createRouteContext(router, parent, outlet, match, params) {
559
559
  load
560
560
  } = match().route;
561
561
  const path = createMemo(() => match().path);
562
+ component && component.preload && component.preload();
563
+ const data = load ? load({
564
+ params,
565
+ location,
566
+ intent: intent || "initial"
567
+ }) : undefined;
562
568
  const route = {
563
569
  parent,
564
570
  pattern,
@@ -567,6 +573,7 @@ function createRouteContext(router, parent, outlet, match, params) {
567
573
  outlet: () => component ? createComponent(component, {
568
574
  params,
569
575
  location,
576
+ data,
570
577
  get children() {
571
578
  return outlet();
572
579
  }
@@ -575,12 +582,6 @@ function createRouteContext(router, parent, outlet, match, params) {
575
582
  return resolvePath(base.path(), to, path());
576
583
  }
577
584
  };
578
- component && component.preload && component.preload();
579
- load && load({
580
- params,
581
- location,
582
- intent: intent || "initial"
583
- });
584
585
  return route;
585
586
  }
586
587
 
@@ -1,9 +1,9 @@
1
1
  import type { Component, JSX } from "solid-js";
2
- import type { MatchFilters, RouteLoadFunc, RouterIntegration, RouteSectionProps } from "../types";
2
+ import type { MatchFilters, RouteLoadFunc, RouteDefinition, RouterIntegration, RouteSectionProps } from "../types";
3
3
  export type BaseRouterProps = {
4
4
  base?: string;
5
5
  root?: Component<RouteSectionProps>;
6
- children?: JSX.Element;
6
+ children?: JSX.Element | RouteDefinition | RouteDefinition[];
7
7
  };
8
8
  export declare const createRouterComponent: (router: RouterIntegration) => (props: BaseRouterProps) => JSX.Element;
9
9
  export type RouteProps<S extends string> = {
package/dist/routing.js CHANGED
@@ -350,6 +350,10 @@ export function createRouteContext(router, parent, outlet, match, params) {
350
350
  const { base, location } = router;
351
351
  const { pattern, component, load } = match().route;
352
352
  const path = createMemo(() => match().path);
353
+ component &&
354
+ component.preload &&
355
+ component.preload();
356
+ const data = load ? load({ params, location, intent: intent || "initial" }) : undefined;
353
357
  const route = {
354
358
  parent,
355
359
  pattern,
@@ -359,6 +363,7 @@ export function createRouteContext(router, parent, outlet, match, params) {
359
363
  ? createComponent(component, {
360
364
  params,
361
365
  location,
366
+ data,
362
367
  get children() {
363
368
  return outlet();
364
369
  }
@@ -368,9 +373,5 @@ export function createRouteContext(router, parent, outlet, match, params) {
368
373
  return resolvePath(base.path(), to, path());
369
374
  }
370
375
  };
371
- component &&
372
- component.preload &&
373
- component.preload();
374
- load && load({ params, location, intent: intent || "initial" });
375
376
  return route;
376
377
  }
package/dist/types.d.ts CHANGED
@@ -47,18 +47,19 @@ export interface RouteLoadFuncArgs {
47
47
  location: Location;
48
48
  intent: Intent;
49
49
  }
50
- export type RouteLoadFunc = (args: RouteLoadFuncArgs) => void;
51
- export interface RouteSectionProps {
50
+ export type RouteLoadFunc<T = unknown> = (args: RouteLoadFuncArgs) => T;
51
+ export interface RouteSectionProps<T = unknown> {
52
52
  params: Params;
53
53
  location: Location;
54
+ data?: T;
54
55
  children?: JSX.Element;
55
56
  }
56
- export type RouteDefinition<S extends string | string[] = any> = {
57
+ export type RouteDefinition<S extends string | string[] = any, T = unknown> = {
57
58
  path?: S;
58
59
  matchFilters?: MatchFilters<S>;
59
- load?: RouteLoadFunc;
60
+ load?: RouteLoadFunc<T>;
60
61
  children?: RouteDefinition | RouteDefinition[];
61
- component?: Component<RouteSectionProps>;
62
+ component?: Component<RouteSectionProps<T>>;
62
63
  };
63
64
  export type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean);
64
65
  export type PathParams<P extends string | readonly string[]> = P extends `${infer Head}/${infer Tail}` ? [...PathParams<Head>, ...PathParams<Tail>] : P extends `:${infer S}?` ? [S] : P extends `:${infer S}` ? [S] : P extends `*${infer S}` ? [S] : [];
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "0.10.1",
9
+ "version": "0.10.2",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",