Skip to content

Commit 2bca471

Browse files
committed
Add unstable to public API (#12917)
1 parent a57d971 commit 2bca471

File tree

20 files changed

+456
-408
lines changed

20 files changed

+456
-408
lines changed

.changeset/client-context.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

.changeset/middleware.md

Lines changed: 44 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,18 @@
44

55
Support `middleware` on routes (unstable)
66

7-
Routes can now define a `middleware` property accepting an array of functions that will run sequentially before route loader run in parallel. These functions accept the same arguments as `loader`/`action` and an additional `next` function to run the remaining data pipeline. This allows middlewares to perform logic before and after loaders/actions execute.
7+
Routes can now define an array of middleware functions that will run sequentially before route handlers run. These functions accept the same arguments as `loader`/`action` plus an additional `next` function to run the remaining data pipeline. This allows middlewares to perform logic before and after handlers execute.
88

99
```tsx
1010
// Framework mode
11-
export const middleware = [logger, auth];
11+
export const unstable_middleware = [serverLogger, serverAuth];
12+
export const unstable_clientMiddleware = [clientLogger];
1213

1314
// Library mode
1415
const routes = [
1516
{
1617
path: "/",
17-
middleware: [logger, auth],
18+
unstable_middleware: [clientLogger, clientAuth],
1819
loader: rootLoader,
1920
Component: Root,
2021
},
@@ -24,49 +25,75 @@ const routes = [
2425
Here's a simple example of a client-side logging middleware that can be placed on the root route:
2526

2627
```tsx
27-
const logger: MiddlewareFunction = ({ request, params, context }, next) => {
28+
async function clientLogger({
29+
request,
30+
params,
31+
context,
32+
next,
33+
}: Route.ClientMiddlewareArgs) {
2834
let start = performance.now();
2935

3036
// Run the remaining middlewares and all route loaders
3137
await next();
3238

3339
let duration = performance.now() - start;
34-
console.log(request.status, request.method, request.url, `(${duration}ms)`);
35-
};
40+
console.log(`Navigated to ${request.url} (${duration}ms)`);
41+
}
42+
```
43+
44+
Note that in the above example, the `next`/`middleware` functions don't return anything. This is by design as on the client there is no "response" to send over the network like there would be for middlewares running on the server. The data is all handled behind the scenes by the stateful `router`.
45+
46+
For a server-side middleware, the `next` function will return the HTTP `Response` that React Router will be sending across the wire, thus giving you a chance to make changes as needed. You may throw a new response to short circuit and respond immediately, or you may return a new or altered response to override the default returned by `next()`.
47+
48+
```tsx
49+
async function serverLogger({
50+
request,
51+
params,
52+
context,
53+
next,
54+
}: Route.MiddlewareArgs) {
55+
let start = performance.now();
56+
57+
// 👇 Grab the response here
58+
let res = await next();
59+
let duration = performance.now() - start;
60+
console.log(`Navigated to ${request.url} (${duration}ms)`);
61+
62+
// 👇 And return it here
63+
return res;
64+
}
3665
```
3766

3867
You can throw a redirect from a middleware to short circuit any remaining processing:
3968

4069
```tsx
41-
const auth: MiddlewareFunction = ({ request, params, context }, next) => {
42-
let user = session.get("user");
70+
function serverAuth({ request, params, context, next }: Route.MiddlewareArgs) {
71+
let user = context.session.get("user");
4372
if (!user) {
44-
session.set("returnTo", request.url);
73+
context.session.set("returnTo", request.url);
4574
throw redirect("/login", 302);
4675
}
4776
context.user = user;
4877
// No need to call next() if you don't need to do any post processing
49-
};
78+
}
5079
```
5180

52-
Note that in the above example, the `next`/`middleware` functions don't return anything. This is by design as on the client there is no "response" to send over the network like there would be for middlewares running on the server. The data is all handled behind the scenes by the stateful `router`.
53-
54-
For a server-side middleware, the `next` function will return the HTTP `Response` that React Router will be sending across the wire, thus giving you a chance to make changes as needed. You may throw a new response to short circuit and respond immediately, or you may return a new or altered response to override the default returned by `next()`.
81+
Here's another example of using a server middleware to detect 404s and check the CMS for a redirect:
5582

5683
```tsx
57-
const redirects: MiddlewareFunction({ request }, next) {
84+
async function redirects({ request, next }: Route.MiddlewareArgs) {
5885
// attempt to handle the request
59-
let response = await next();
86+
let res = await next();
6087

6188
// if it's a 404, check the CMS for a redirect, do it last
6289
// because it's expensive
63-
if (response.status === 404) {
90+
if (res.status === 404) {
6491
let cmsRedirect = await checkCMSRedirects(request.url);
6592
if (cmsRedirect) {
6693
throw redirect(cmsRedirect, 302);
6794
}
6895
}
6996

70-
return response;
97+
return res;
7198
}
7299
```

.changeset/spa-context.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
---
2-
"react-router": minor
2+
"react-router": patch
33
---
44

5-
Add `context` support to client side data routers (`createBrowsertRouter`, etc.)
5+
Add `context` support to client side data routers (unstable)
6+
7+
- Library mode
8+
- `createBrowserRouter(routes, { unstable_context })`
9+
- Framework mode
10+
- `<HydratedRouter unstable_context>`

integration/browser-entry-test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ test("allows users to pass a client side context to HydratedRouter", async ({
9595
hydrateRoot(
9696
document,
9797
<StrictMode>
98-
<HydratedRouter context={{ foo: 'bar' }} />
98+
<HydratedRouter unstable_context={{ foo: 'bar' }} />
9999
</StrictMode>
100100
);
101101
});

0 commit comments

Comments
 (0)