You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<docs-warning>The middleware feature is currently experimental and subject to breaking changes. Use the `future.unstable_middleware` flag to enable it.</docs-warning>
9
9
10
-
Middleware allows you to run code before and after your route handlers (loaders, actions, and components) execute. This enables common patterns like authentication, logging, error handling, and data preprocessing in a reusable way.
10
+
Middleware allows you to run code before and after the `Response` generation for the matched path. This enables common patterns like authentication, logging, error handling, and data preprocessing in a reusable way.
11
11
12
-
Middleware runs in a nested chain, executing from parent routes to child routes on the way "down" to your route handlers, then from child routes back to parent routes on the way "up" after your handlers complete.
12
+
Middleware runs in a nested chain, executing from parent routes to child routes on the way "down" to your route handlers, then from child routes back to parent routes on the way "up" after a `Response` is generated.
13
13
14
14
For example, on a `GET /parent/child` request, the middleware would run in the following order:
15
15
16
16
```text
17
17
- Root middleware start
18
18
- Parent middleware start
19
19
- Child middleware start
20
-
- Run loaders
20
+
- Run loaders, generate HTML Response
21
21
- Child middleware end
22
22
- Parent middleware end
23
23
- Root middleware end
@@ -39,11 +39,12 @@ export default {
39
39
} satisfiesConfig;
40
40
```
41
41
42
-
<docs-warning>By enabling the middleware feature, you change the type of the `context` parameter to your loaders and actions. Please pay attention to the section on [getLoadContext](#custom-server-with-getloadcontext) below if you are actively using `context` today.</docs-warning>
42
+
<docs-warning>By enabling the middleware feature, you change the type of the `context` parameter to your loaders and actions. Please pay attention to the section on [getLoadContext](#changes-to-getloadcontextapploadcontext) below if you are actively using `context` today.</docs-warning>
43
43
44
44
### 2. Create a context
45
45
46
-
Create type-safe context objects using `unstable_createContext`:
46
+
Middleware uses a `context` provider instance to provide data down the middleware chain.
47
+
You can create type-safe context objects using `unstable_createContext`:
@@ -104,6 +105,22 @@ export default function Dashboard({
104
105
}
105
106
```
106
107
108
+
#### 4. Update your `getLoadContext` function (if applicable)
109
+
110
+
If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return a Map of contexts and values, instead of a JavaScript object:
111
+
112
+
```diff
113
+
+import { unstable_createContext } from "react-router";
The new context system provides type safety and prevents naming conflicts:
194
+
`next()` is not designed to throw errors under normal conditions, so you generally shouldn't find yourself wrapping `next` in a `try`/`catch`. The responsibility of the `next()` function is to return a `Response` for the current `Request`, so as long as that can be completed, `next()` will return the Response and won't `throw`. Even if a `loader` throws an error, or a component fails to render, React Router already handles those by rendering the nearest `ErrorBoundary`, so a Response is still generated without issue.
195
+
196
+
This behavior is important to allow middleware patterns such as automatically setting required headers on outgoing responses (i.e., committing a session) from a root middleware. If any error caused that to throw, we'd miss the execution of ancestor middleware son thew way out and those required headers wouldn't be set.
197
+
198
+
The only cases in which `next()`_should_ throw are if we fail to generate a Response. There's a few ways in which this could happen:
199
+
200
+
- A middleware can short circuit the rest of the request and throw a `Response` (usually a `redirect`)
201
+
- If the logic directly inside of a middleware function throws, that will cause the ancestor `next()` function to throw
202
+
203
+
## Changes to `getLoadContext`/`AppLoadContext`
204
+
205
+
<docs-info>This only applies if you are using a custom server and a custom `getLoadContext` function</docs-info>
206
+
207
+
Middleware introduces a breaking change to the `context` parameter generated by `getLoadContext` and passed to your loaders and actions. The current approach of a module-augmented `AppLoadContext` isn't really type-safe and instead just sort of tells TypeScript to "trust me".
208
+
209
+
Middleware needs an equivalent `context` on the client for `clientMiddleware`, but we didn't want to duplicate this pattern from the server that we already weren't thrilled with, so we decided to introduce a new API where we could tackle type-safety.
210
+
211
+
When opting into middleware, the `context` parameter changes to an instance of `RouterContextProvider`:
158
212
159
213
```ts
160
-
// ✅ Type-safe
214
+
let dbContext =unstable_createContext<Database>();
215
+
let context =newunstable_RouterContextProvider();
216
+
context.set(dbContext, getDb());
217
+
// ^ type-safe
218
+
let db =context.get(dbContext);
219
+
// ^ Database
220
+
```
221
+
222
+
If you're using a custom server and a `getLoadContext` function, you will need to update your implementation to return a `Map` of contexts and values, instead of a JavaScript object:
223
+
224
+
```diff
225
+
+import { unstable_createContext } from "react-router";
0 commit comments