Skip to content

Commit 65a8ee1

Browse files
authored
Making Router "plugins" prop required (#207)
1 parent b3d6dbd commit 65a8ee1

File tree

22 files changed

+151
-235
lines changed

22 files changed

+151
-235
lines changed

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,14 @@ import {
122122
RouteComponent,
123123
createBrowserHistory,
124124
} from 'react-resource-router';
125+
import { createResourcesPlugin } from 'react-resource-router/resources';
125126
import { appRoutes } from './routing/routes';
126127

127128
const history = createBrowserHistory();
129+
const resourcesPlugin = createResourcesPlugin({});
128130

129131
const App = () => (
130-
<Router routes={appRoutes} history={history}>
132+
<Router routes={appRoutes} history={history} plugins={[resourcesPlugin]}>
131133
<RouteComponent />
132134
</Router>
133135
);

docs/api/components.md

+52-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Router
22

3-
The `Router` component should ideally wrap your client app as high up in the tree as possible. As soon as it is mounted, it will match the current route and then call all of the matched resources' `getData` methods. Components that are subscribed to these resources either via the [`useResource`](./hooks.md#useresource) hook or [`ResourceSubscriber`](./components.md#resourcesubscriber) will progressively update according to the requests' lifecycles.
3+
The `Router` component should ideally wrap your client app as high up in the tree as possible.
44

55
If you are planning to render your application on the server, we recommend creating a composition boundary between your router and the core of your application, including your `RouteComponent`.
66

@@ -19,10 +19,13 @@ export const App = () => (
1919
```js
2020
// index.js
2121
import { Router, createBrowserHistory } from 'react-resource-router';
22+
import { createResourcesPlugin } from 'react-resource-router/resources';
2223
import { App } from './components';
2324
import { appRoutes } from './routing';
2425

25-
<Router history={createBrowserHistory()} routes={appRoutes}>
26+
const resourcesPlugin = createResourcesPlugin({});
27+
28+
<Router history={createBrowserHistory()} routes={appRoutes} plugins={[resourcesPlugin]}>
2629
<App />
2730
</Router>;
2831
```
@@ -33,12 +36,54 @@ import { appRoutes } from './routing';
3336
| ----------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
3437
| `routes` | `Routes[]` | Your application's routes |
3538
| `history` | `History` | The history instance for the router, if omitted memory history will be used (optional but recommended) |
39+
| `plugins` | `Plugin[]` | Plugin allows you to hook into Router API and extra login on route load/prefetch/etc |
3640
| `basePath` | `string` | Base path string that will get prepended to all route paths (optional) |
3741
| `initialRoute` | `Route` | The route your application is initially showing, it's a performance optimisation to avoid route matching cost on initial render(optional) |
38-
| `resourceContext` | `ResourceContext` | Custom contextual data that will be provided to all your resources' `getKey` and `getData` methods (optional) |
39-
| `resourceData` | `ResourceData` | Pre-resolved resource data. When provided, the router will not request resources on mount (optional) |
4042
| `onPrefetch` | `function(RouterContext)` | Called when prefetch is triggered from a Link (optional) |
4143

44+
## Resources plugin
45+
46+
Resources plugin enables `resources` prop on the `Route` definition
47+
48+
As soon as `Router` is mounted, it will match the current route and then call all of the matched resources' `getData` methods. Components that are subscribed to these resources either via the [`useResource`](./hooks.md#useresource) hook or [`ResourceSubscriber`](./components.md#resourcesubscriber) will progressively update according to the requests' lifecycles.
49+
50+
```js
51+
// index.js
52+
import { Router, createBrowserHistory } from 'react-resource-router';
53+
import { createResourcesPlugin } from 'react-resource-router/resources';
54+
import { App } from './components';
55+
56+
const resourcesPlugin = createResourcesPlugin({ ... });
57+
58+
export const routes = [
59+
{
60+
path: '/home',
61+
name: 'HOME',
62+
component: Home,
63+
resources: [homeResource],
64+
},
65+
{
66+
path: '/about',
67+
name: 'ABOUT',
68+
component: About,
69+
resources: [aboutResource],
70+
},
71+
];
72+
73+
<Router history={createBrowserHistory()} routes={routes} plugins={[resourcesPlugin]}>
74+
<App />
75+
</Router>;
76+
```
77+
78+
### Resources plugin props
79+
80+
| prop | type | description |
81+
| ----------------- | ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
82+
| `context` | `ResourceContext` | Custom contextual data that will be provided to all your resources' `getKey` and `getData` methods (optional) |
83+
| `resourceData` | `ResourceData` | Pre-resolved resource data. When provided, the router will not request resources on mount (optional) |
84+
| `timeout` | `number` | `timout` is used to prevent slow APIs from causing long renders on the server, If a route resource does not return within the specified time then its data and promise will be set to null.(optional) |
85+
86+
4287
## MemoryRouter
4388

4489
The `MemoryRouter` component can be used for your application's unit tests.
@@ -143,13 +188,15 @@ import {
143188
Router,
144189
RouteComponent,
145190
} from 'react-resource-router';
191+
import { createResourcesPlugin } from 'react-resource-router/resources';
146192
import { StaticNavigation } from '../components';
147193
import { routes } from '../routing';
148194

149195
const history = createBrowserHistory();
196+
const resourcesPlugin = createResourcesPlugin({});
150197

151198
export const App = () => (
152-
<Router history={history} routes={routes}>
199+
<Router history={history} routes={routes} plugins={[resourcesPlugin]}>
153200
<StaticNavigation />
154201
<RouteComponent />
155202
</Router>

docs/router/ssr.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,30 @@ export const ClientApp = () => (
6666

6767
Until React Suspense works on the server, we cannot do progressive rendering server side. To get around this, we need to `await` all resource requests to render our app _with all our resource data_ on the server.
6868

69-
Luckily the `Router` provides a convenient static method to do this for us.
69+
Luckily we have a convenient static method `invokePluginLoad` to do this for us.
7070

7171
```js
7272
import { renderToString } from 'react-dom/server';
7373
import { Router } from 'react-resource-router';
74+
import { createResourcesPlugin } from 'react-resource-router/resources';
7475
import { routes } from '../routing/routes';
7576
import { ServerApp } from './app';
7677

7778
const renderToStringWithData = async ({ location }) => {
78-
await Router.requestResources({ location, routes });
79+
const resourcesPlugin = createResourcesPlugin({});
80+
81+
invokePluginLoad([resourcesPlugin], {
82+
history: createMemoryHistory({ initialEntries: [location] }),
83+
routes,
84+
basePath: '...',
85+
});
86+
87+
const resourceData = await resourcesPlugin.getSerializedResources();
7988

8089
return renderToString(<ServerApp location={location} />);
8190
};
8291
```
8392

8493
Notice that we do not need to provide any `resourceData` object to the `ServerApp`, the `Router` handles this for us internally.
8594

86-
To prevent slow APIs from causing long renders on the server you can optionally pass in `timeout` as an option to `Router.requestResources`. If a route resource does not return within the specified time then its data and promise will be set to null.
95+
To prevent slow APIs from causing long renders on the server you can optionally pass in `timeout` as an option to `createResourcesPlugin({ timeout: ... })`. If a route resource does not return within the specified time then its data and promise will be set to null.

examples/basic-routing/index.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@ const appRoutes = [
3131

3232
const App = () => {
3333
return (
34-
<Router basePath="/basic-routing" history={myHistory} routes={appRoutes}>
34+
<Router
35+
basePath="/basic-routing"
36+
history={myHistory}
37+
routes={appRoutes}
38+
plugins={[]}
39+
>
3540
<RouteComponent />
3641
</Router>
3742
);

examples/hash-routing/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const routes = [
3636

3737
const App = () => {
3838
return (
39-
<Router history={history} routes={routes}>
39+
<Router history={history} routes={routes} plugins={[]}>
4040
<RouteComponent />
4141
</Router>
4242
);

examples/hooks/index.tsx

+9-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
createBrowserHistory,
1414
createRouterSelector,
1515
} from 'react-resource-router';
16+
import { createResourcesPlugin } from 'react-resource-router/resources';
1617

1718
const myHistory = createBrowserHistory();
1819
const useRouteName = createRouterSelector(s => s.route.name);
@@ -51,9 +52,16 @@ const Title = () => {
5152
return <p>Page: {title}</p>;
5253
};
5354

55+
const resourcesPlugin = createResourcesPlugin({});
56+
5457
const App = () => {
5558
return (
56-
<Router basePath="/hooks" history={myHistory} routes={appRoutes}>
59+
<Router
60+
basePath="/hooks"
61+
history={myHistory}
62+
routes={appRoutes}
63+
plugins={[resourcesPlugin]}
64+
>
5765
<Title />
5866
<RouteComponent />
5967
</Router>

examples/hydration-with-plugins/home.tsx

-29
This file was deleted.

examples/hydration-with-plugins/index.html

-11
This file was deleted.

examples/hydration-with-plugins/index.tsx

-61
This file was deleted.

examples/hydration-with-plugins/routes.tsx

-10
This file was deleted.

examples/hydration/home.tsx

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export const homeResource = createResource({
1212

1313
return result;
1414
},
15-
isBrowserOnly: true,
1615
});
1716

1817
export const Home = () => {

examples/hydration/index.tsx

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { createMemoryHistory } from 'history';
12
import React from 'react';
23
import { render } from 'react-dom';
34
import { defaultRegistry } from 'react-sweet-state';
@@ -8,18 +9,25 @@ import {
89
Router,
910
RouteComponent,
1011
createBrowserHistory,
12+
invokePluginLoad,
1113
} from 'react-resource-router';
14+
import { createResourcesPlugin } from 'react-resource-router/resources';
1215

1316
const myHistory = createBrowserHistory();
1417

1518
const appRoutes = [homeRoute];
1619

1720
const getStateFromServer = async () => {
18-
const resourceData = await Router.requestResources({
19-
location: '/',
21+
const resourcesPlugin = createResourcesPlugin({});
22+
23+
invokePluginLoad([resourcesPlugin], {
24+
history: createMemoryHistory({ initialEntries: [location] }),
2025
routes: appRoutes,
26+
basePath: '/hydration-with-plugins',
2127
});
2228

29+
const resourceData = await resourcesPlugin.getSerializedResources();
30+
2331
// clearing the store
2432
defaultRegistry.stores.clear();
2533

@@ -28,13 +36,16 @@ const getStateFromServer = async () => {
2836

2937
const main = async () => {
3038
const data = await getStateFromServer();
39+
const resourcesPlugin = createResourcesPlugin({
40+
resourceData: data,
41+
});
3142

3243
const App = () => {
3344
return (
3445
<Router
35-
basePath="/hydration"
46+
basePath="/hydration-with-plugins"
3647
history={myHistory}
37-
resourceData={data}
48+
plugins={[resourcesPlugin]}
3849
routes={appRoutes}
3950
>
4051
<RouteComponent />

examples/routing-with-resources/index.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
RouteComponent,
99
createBrowserHistory,
1010
} from 'react-resource-router';
11+
import { createResourcesPlugin } from 'react-resource-router/resources';
1112

1213
const myHistory = createBrowserHistory();
1314

@@ -20,6 +21,7 @@ const App = () => {
2021
history={myHistory}
2122
onPrefetch={({ route }) => console.log('Prefetching route', route.name)}
2223
routes={appRoutes}
24+
plugins={[createResourcesPlugin({})]}
2325
>
2426
<RouteComponent />
2527
</Router>

0 commit comments

Comments
 (0)