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
Copy file name to clipboardExpand all lines: decisions/0014-context-middleware.md
+29-3Lines changed: 29 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -24,9 +24,13 @@ We've done a lot of work since then to get us to a place where we could ship a m
24
24
25
25
### Leverage a new type-safe `context` API
26
26
27
-
We originally considered leaning on our existing `context` value we pass to server-side `loader` and `action` functions, and implementing a similar client-side equivalent for parity. However, the type story around `AppLoadContext` isn't great, so that would mean implementing a new API client side that we knew we weren't happy with from day one. And then likely replacing it with a better version fairly soon after.
27
+
We originally considered leaning on our existing `context`(`type AppLoadContext`) value we pass to server-side `loader` and `action` functions as the `context` for middleware functions. Using this would make for an easier adoption of middleware for apps that use `AppLoadContext` today. However, there were a few downsides to that approach.
28
28
29
-
Instead, when the flag is enabled, we'll be replacing `AppLoadContext` with a new type-safe `context` API that is similar in usage to the `React.createContext` API:
29
+
First, the type story is lacking because it's just a global interface you augment via declaration merging so it's not true type safety and is more of a "trust me on this" scenario. We've always known it wasn't a great typed API and have always assumed we'd enhance it at some point via a breaking change behind a future flag. The introduction of middleware should result in much _more_ usage of `context` than exists today since it'll open up to user of `react-router-serve` as well, so it made more sense to ship the breaking change flag now for the smaller surface area of `context`-enabled apps users, ionstead of later for a much larger surface area of apps.
30
+
31
+
Second, in order to implement client-side middleware, we need to introduce a new `context` concept on the client - and we would like that to be the same API as we have on the server. So, if we chose to stick with `AppLoadContext`, we'd then have to implement a brand new `ClientAppLoadContext` which would suffer the same type issues out of the gate. So it felt lazy to ship a known-subpar-API to the client. Furthermore, even iof we did ship it - we'd _still_ want to enhance it later - so we'd be shipping a mediocre client `context` API _knowing_ that we would be breaking shortly after with a better typed API.
32
+
33
+
So, we decided to rip the band-aid off and include the breaking `context` change with the initial release of middleware. When the flag is enabled, we'll be replacing `AppLoadContext` with a new type-safe `context` API that is similar in usage to the `React.createContext` API:
If you have an app already using `AppLoadContext`, you don't need to split that out and can just stick that object into it's own context value and maintain the same shape:
56
+
57
+
```diff
58
+
+ let appContext = unstable_createContext<AppLoadContext>()
59
+
60
+
function getLoadContext(req, res) {
61
+
let appLoadContext = { /* your existing object */ };
62
+
63
+
- return appLoadContext
64
+
+ return new Map([[appContext, appLoadContext]]);
65
+
}
66
+
67
+
function loader({ context }) {
68
+
- context.foo.something();
69
+
+ // Hopefully this can be done via find/replace or a codemod
70
+
+ context.get(appContext).foo.something()
71
+
// ...
72
+
}
73
+
```
74
+
51
75
#### Client Side Context
52
76
53
-
In order to support the same API on the client, we will also add support for a client-side `context`value which is already a [long requested feature][client-context]. If you need to provide initial values (similar to `getLoadContext` on the server), you can do so with a new `getContext` method which returns a `Map<RouterContext, unknown>`:
77
+
In order to support the same API on the client, we will also add support for a client-side `context`of the same type (which is already a [long requested feature][client-context]). If you need to provide initial values (similar to `getLoadContext` on the server), you can do so with a new `getContext` method which returns a `Map<RouterContext, unknown>`:
54
78
55
79
```ts
80
+
let loggerContext =unstable_createContext<(...args:unknown[]) =>void>();
0 commit comments