Skip to content

Commit dc6917e

Browse files
feat(react-router): add loaderData and deprecate data where possible (#14047)
1 parent 88beda8 commit dc6917e

File tree

9 files changed

+77
-3
lines changed

9 files changed

+77
-3
lines changed

.changeset/rare-pears-walk.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"react-router": minor
3+
---
4+
5+
Add `loaderData` arguments/properties alongside existing `data` arguments/properties to provide consistency and clarity between `loaderData` and `actionData` across the board
6+
- Updated types: `Route.MetaArgs`, `Route.MetaMatch`, `MetaArgs`, `MetaMatch`, `Route.ComponentProps.matches`, `UIMatch`
7+
- `@deprecated` warnings have been added to the existing `data` properties to point users to new `loaderData` properties, in preparation for removing the `data` properties in a future major release

integration/catch-boundary-test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,13 @@ test.describe("ErrorBoundary (thrown responses)", () => {
255255

256256
// Root loader data sticks around from previous load
257257
let expected = JSON.stringify([
258-
{ id: "root", pathname: "", params: {}, data: { data: "ROOT LOADER" } },
258+
{
259+
id: "root",
260+
pathname: "",
261+
params: {},
262+
data: { data: "ROOT LOADER" },
263+
loaderData: { data: "ROOT LOADER" },
264+
},
259265
]);
260266
expect(await app.getHtml("#matches")).toContain(expected);
261267
});

integration/matches-test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ test.describe("useMatches", () => {
109109
"pathname": "/",
110110
"params": {},
111111
"data": "ROOT",
112+
"loaderData": "ROOT",
112113
"handle": {
113114
"stuff": "root handle"
114115
}
@@ -118,6 +119,7 @@ test.describe("useMatches", () => {
118119
"pathname": "/",
119120
"params": {},
120121
"data": "INDEX",
122+
"loaderData": "INDEX",
121123
"handle": {
122124
"stuff": "index handle"
123125
}
@@ -135,6 +137,7 @@ test.describe("useMatches", () => {
135137
"pathname": "/",
136138
"params": {},
137139
"data": "ROOT",
140+
"loaderData": "ROOT",
138141
"handle": {
139142
"stuff": "root handle"
140143
}
@@ -144,6 +147,7 @@ test.describe("useMatches", () => {
144147
"pathname": "/",
145148
"params": {},
146149
"data": "INDEX",
150+
"loaderData": "INDEX",
147151
"handle": {
148152
"stuff": "index handle"
149153
}
@@ -164,6 +168,7 @@ test.describe("useMatches", () => {
164168
"pathname": "/",
165169
"params": {},
166170
"data": "ROOT",
171+
"loaderData": "ROOT",
167172
"handle": {
168173
"stuff": "root handle"
169174
}
@@ -173,6 +178,7 @@ test.describe("useMatches", () => {
173178
"pathname": "/about",
174179
"params": {},
175180
"data": "ABOUT",
181+
"loaderData": "ABOUT",
176182
"handle": {
177183
"stuff": "about handle"
178184
}

packages/react-router/__tests__/data-memory-router-test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -812,13 +812,15 @@ describe("createMemoryRouter", () => {
812812
expect(spy).toHaveBeenCalledWith("Layout", [
813813
{
814814
data: undefined,
815+
loaderData: undefined,
815816
handle: undefined,
816817
id: "0",
817818
params: {},
818819
pathname: "/",
819820
},
820821
{
821822
data: "BAR LOADER",
823+
loaderData: "BAR LOADER",
822824
handle: {
823825
key: "value",
824826
},

packages/react-router/__tests__/dom/data-static-router-test.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ describe("A <StaticRouterProvider>", () => {
115115
data: {
116116
key1: "value1",
117117
},
118+
loaderData: {
119+
key1: "value1",
120+
},
118121
handle: "1",
119122
id: "0",
120123
params: {},
@@ -124,6 +127,9 @@ describe("A <StaticRouterProvider>", () => {
124127
data: {
125128
key2: "value2",
126129
},
130+
loaderData: {
131+
key2: "value2",
132+
},
127133
handle: "2",
128134
id: "0-0",
129135
params: {},
@@ -149,6 +155,9 @@ describe("A <StaticRouterProvider>", () => {
149155
data: {
150156
key1: "value1",
151157
},
158+
loaderData: {
159+
key1: "value1",
160+
},
152161
handle: "1",
153162
id: "0",
154163
params: {},
@@ -158,6 +167,9 @@ describe("A <StaticRouterProvider>", () => {
158167
data: {
159168
key2: "value2",
160169
},
170+
loaderData: {
171+
key2: "value2",
172+
},
161173
handle: "2",
162174
id: "0-0",
163175
params: {},
@@ -262,6 +274,9 @@ describe("A <StaticRouterProvider>", () => {
262274
data: {
263275
key1: "value1",
264276
},
277+
loaderData: {
278+
key1: "value1",
279+
},
265280
handle: "1",
266281
id: "0",
267282
params: {},
@@ -271,6 +286,9 @@ describe("A <StaticRouterProvider>", () => {
271286
data: {
272287
key2: "value2",
273288
},
289+
loaderData: {
290+
key2: "value2",
291+
},
274292
handle: "2",
275293
id: "0-0",
276294
params: {},
@@ -296,6 +314,9 @@ describe("A <StaticRouterProvider>", () => {
296314
data: {
297315
key1: "value1",
298316
},
317+
loaderData: {
318+
key1: "value1",
319+
},
299320
handle: "1",
300321
id: "0",
301322
params: {},
@@ -305,6 +326,9 @@ describe("A <StaticRouterProvider>", () => {
305326
data: {
306327
key2: "value2",
307328
},
329+
loaderData: {
330+
key2: "value2",
331+
},
308332
handle: "2",
309333
id: "0-0",
310334
params: {},

packages/react-router/lib/dom/ssr/components.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,7 @@ export function Meta(): React.JSX.Element {
541541
let match: MetaMatch = {
542542
id: routeId,
543543
data,
544+
loaderData: data,
544545
meta: [],
545546
params: _match.params,
546547
pathname: _match.pathname,
@@ -554,6 +555,7 @@ export function Meta(): React.JSX.Element {
554555
typeof routeModule.meta === "function"
555556
? (routeModule.meta as MetaFunction)({
556557
data,
558+
loaderData: data,
557559
params,
558560
location,
559561
matches,

packages/react-router/lib/dom/ssr/routeModules.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,13 @@ export interface MetaMatch<
130130
> {
131131
id: RouteId;
132132
pathname: DataRouteMatch["pathname"];
133+
/** @deprecated Use `MetaMatch.loaderData` instead */
133134
data: Loader extends LoaderFunction | ClientLoaderFunction
134135
? SerializeFrom<Loader>
135136
: unknown;
137+
loaderData: Loader extends LoaderFunction | ClientLoaderFunction
138+
? SerializeFrom<Loader>
139+
: unknown;
136140
handle?: RouteHandle;
137141
params: DataRouteMatch["params"];
138142
meta: MetaDescriptor[];
@@ -160,11 +164,17 @@ export interface MetaArgs<
160164
LoaderFunction | ClientLoaderFunction | unknown
161165
> = Record<string, unknown>,
162166
> {
167+
/** @deprecated Use `MetaArgs.loaderData` instead */
163168
data:
164169
| (Loader extends LoaderFunction | ClientLoaderFunction
165170
? SerializeFrom<Loader>
166171
: unknown)
167172
| undefined;
173+
loaderData:
174+
| (Loader extends LoaderFunction | ClientLoaderFunction
175+
? SerializeFrom<Loader>
176+
: unknown)
177+
| undefined;
168178
params: Params;
169179
location: Location;
170180
matches: MetaMatches<MatchLoaders>;

packages/react-router/lib/router/utils.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,14 @@ export interface UIMatch<Data = unknown, Handle = unknown> {
814814
* {@link https://reactrouter.com/start/framework/routing#dynamic-segments Dynamic route params} for the matched route.
815815
**/
816816
params: AgnosticRouteMatch["params"];
817-
/** The return value from the matched route's loader or clientLoader */
817+
/**
818+
* The return value from the matched route's loader or clientLoader
819+
*
820+
* @deprecated Use `UIMatch.loaderData` instead
821+
*/
818822
data: Data;
823+
/** The return value from the matched route's loader or clientLoader */
824+
loaderData: Data;
819825
/** The {@link https://reactrouter.com/start/framework/route-module#handle handle object} exported from the matched route module */
820826
handle: Handle;
821827
}
@@ -830,6 +836,7 @@ export function convertRouteMatchToUiMatch(
830836
pathname,
831837
params,
832838
data: loaderData[route.id],
839+
loaderData: loaderData[route.id],
833840
handle: route.handle,
834841
};
835842
}

packages/react-router/lib/types/route-module-annotations.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ type MetaMatch<T extends MatchInfo> = Pretty<{
3535
params: Record<string, string | undefined>;
3636
pathname: string;
3737
meta: MetaDescriptor[];
38+
/** @deprecated Use `MetaMatch.loaderData` instead */
3839
data: GetLoaderData<T["module"]>;
40+
loaderData: GetLoaderData<T["module"]>;
3941
handle?: unknown;
4042
error?: unknown;
4143
}>;
@@ -51,8 +53,14 @@ type CreateMetaArgs<T extends RouteInfo> = {
5153
location: Location;
5254
/** {@link https://reactrouter.com/start/framework/routing#dynamic-segments Dynamic route params} for the current route. */
5355
params: T["params"];
54-
/** The return value for this route's server loader function */
56+
/**
57+
* The return value for this route's server loader function
58+
*
59+
* @deprecated Use `Route.MetaArgs.loaderData` instead
60+
*/
5561
data: T["loaderData"] | undefined;
62+
/** The return value for this route's server loader function */
63+
loaderData: T["loaderData"] | undefined;
5664
/** Thrown errors that trigger error boundaries will be passed to the meta function. This is useful for generating metadata for error pages. */
5765
error?: unknown;
5866
/** An array of the current {@link https://api.reactrouter.com/v7/interfaces/react_router.UIMatch.html route matches}, including parent route matches. */
@@ -109,7 +117,9 @@ type Match<T extends MatchInfo> = Pretty<{
109117
id: T["id"];
110118
params: Record<string, string | undefined>;
111119
pathname: string;
120+
/** @deprecated Use `Match.loaderData` instead */
112121
data: GetLoaderData<T["module"]>;
122+
loaderData: GetLoaderData<T["module"]>;
113123
handle: unknown;
114124
}>;
115125

0 commit comments

Comments
 (0)