diff --git a/.changeset/violet-beds-swim.md b/.changeset/violet-beds-swim.md
new file mode 100644
index 0000000000..1acd1fdaa0
--- /dev/null
+++ b/.changeset/violet-beds-swim.md
@@ -0,0 +1,5 @@
+---
+"react-router": minor
+---
+
+Stabilize `unstable_dataStrategy`
diff --git a/integration/defer-loader-test.ts b/integration/defer-loader-test.ts
index 252fed6b10..534716b389 100644
--- a/integration/defer-loader-test.ts
+++ b/integration/defer-loader-test.ts
@@ -28,9 +28,9 @@ test.describe("deferred loaders", () => {
`,
"app/routes/redirect.tsx": js`
- import { unstable_data } from 'react-router';
+ import { data } from 'react-router';
export function loader() {
- return unstable_data(
+ return data(
{ food: "pizza" },
{
status: 301,
diff --git a/integration/single-fetch-test.ts b/integration/single-fetch-test.ts
index b57d86c256..5a780a12a2 100644
--- a/integration/single-fetch-test.ts
+++ b/integration/single-fetch-test.ts
@@ -110,7 +110,7 @@ const files = {
`,
"app/routes/data-with-response.tsx": js`
- import { useActionData, useLoaderData, unstable_data as data } from "react-router";
+ import { useActionData, useLoaderData, data } from "react-router";
export function headers ({ actionHeaders, loaderHeaders, errorHeaders }) {
if ([...actionHeaders].length > 0) {
@@ -253,7 +253,7 @@ test.describe("single-fetch", () => {
});
});
- test("loads proper data (via unstable_data) on single fetch loader requests", async () => {
+ test("loads proper data (via data()) on single fetch loader requests", async () => {
let fixture = await createFixture({
files,
});
@@ -280,7 +280,7 @@ test.describe("single-fetch", () => {
});
});
- test("loads proper data (via unstable_data) on single fetch action requests", async () => {
+ test("loads proper data (via data()) on single fetch action requests", async () => {
let fixture = await createFixture({
files,
});
@@ -505,28 +505,28 @@ test.describe("single-fetch", () => {
expect(urls).toEqual([]);
});
- test("does not revalidate on 4xx/5xx action responses (via unstable_data)", async ({
+ test("does not revalidate on 4xx/5xx action responses (via data())", async ({
page,
}) => {
let fixture = await createFixture({
files: {
...files,
"app/routes/action.tsx": js`
- import { Form, Link, useActionData, useLoaderData, useNavigation, unstable_data } from 'react-router';
+ import { Form, Link, useActionData, useLoaderData, useNavigation, data } from 'react-router';
export async function action({ request }) {
let fd = await request.formData();
if (fd.get('throw') === "5xx") {
- throw unstable_data("Thrown 500", { status: 500 });
+ throw data("Thrown 500", { status: 500 });
}
if (fd.get('throw') === "4xx") {
- throw unstable_data("Thrown 400", { status: 400 });
+ throw data("Thrown 400", { status: 400 });
}
if (fd.get('return') === "5xx") {
- return unstable_data("Returned 500", { status: 500 });
+ return data("Returned 500", { status: 500 });
}
if (fd.get('return') === "4xx") {
- return unstable_data("Returned 400", { status: 400 });
+ return data("Returned 400", { status: 400 });
}
return null;
}
diff --git a/packages/react-router/__tests__/data-memory-router-test.tsx b/packages/react-router/__tests__/data-memory-router-test.tsx
index 3375d47fde..67bb418f18 100644
--- a/packages/react-router/__tests__/data-memory-router-test.tsx
+++ b/packages/react-router/__tests__/data-memory-router-test.tsx
@@ -3292,7 +3292,7 @@ describe("createMemoryRouter", () => {
/>
),
- { initialEntries: ["/foo"], unstable_dataStrategy: urlDataStrategy }
+ { initialEntries: ["/foo"], dataStrategy: urlDataStrategy }
);
let { container } = render();
diff --git a/packages/react-router/__tests__/router/ssr-test.ts b/packages/react-router/__tests__/router/ssr-test.ts
index 29263b984c..fb58a9a16d 100644
--- a/packages/react-router/__tests__/router/ssr-test.ts
+++ b/packages/react-router/__tests__/router/ssr-test.ts
@@ -1403,7 +1403,7 @@ describe("ssr", () => {
let { query } = createStaticHandler(SSR_ROUTES);
let context = await query(createRequest("/custom"), {
- unstable_dataStrategy: urlDataStrategy,
+ dataStrategy: urlDataStrategy,
});
expect(context).toMatchObject({
actionData: null,
@@ -2251,7 +2251,7 @@ describe("ssr", () => {
let data;
data = await queryRoute(createRequest("/custom"), {
- unstable_dataStrategy: urlDataStrategy,
+ dataStrategy: urlDataStrategy,
});
expect(data).toBeInstanceOf(URLSearchParams);
expect((data as URLSearchParams).get("foo")).toBe("bar");
diff --git a/packages/react-router/__tests__/router/utils/data-router-setup.ts b/packages/react-router/__tests__/router/utils/data-router-setup.ts
index a5724065d7..d0532819fb 100644
--- a/packages/react-router/__tests__/router/utils/data-router-setup.ts
+++ b/packages/react-router/__tests__/router/utils/data-router-setup.ts
@@ -339,7 +339,7 @@ export function setup({
routes: enhanceRoutes(routes),
hydrationData,
window: testWindow,
- unstable_dataStrategy: dataStrategy,
+ dataStrategy: dataStrategy,
});
let fetcherData = getFetcherData(currentRouter);
diff --git a/packages/react-router/index.ts b/packages/react-router/index.ts
index 1cde18d67b..993dc1f048 100644
--- a/packages/react-router/index.ts
+++ b/packages/react-router/index.ts
@@ -23,10 +23,10 @@ export type {
export type {
ActionFunction,
ActionFunctionArgs,
- DataStrategyFunction as unstable_DataStrategyFunction,
- DataStrategyFunctionArgs as unstable_DataStrategyFunctionArgs,
- DataStrategyMatch as unstable_DataStrategyMatch,
- DataStrategyResult as unstable_DataStrategyResult,
+ DataStrategyFunction,
+ DataStrategyFunctionArgs,
+ DataStrategyMatch,
+ DataStrategyResult,
DataWithResponseInit as UNSAFE_DataWithResponseInit,
ErrorResponse,
FormEncType,
@@ -58,7 +58,7 @@ export {
IDLE_BLOCKER,
} from "./lib/router/router";
export {
- data as unstable_data,
+ data,
generatePath,
isRouteErrorResponse,
json,
diff --git a/packages/react-router/lib/components.tsx b/packages/react-router/lib/components.tsx
index 2dddec9e40..fc5c3f5462 100644
--- a/packages/react-router/lib/components.tsx
+++ b/packages/react-router/lib/components.tsx
@@ -144,7 +144,7 @@ export function createMemoryRouter(
hydrationData?: HydrationState;
initialEntries?: InitialEntry[];
initialIndex?: number;
- unstable_dataStrategy?: DataStrategyFunction;
+ dataStrategy?: DataStrategyFunction;
patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
}
): RemixRouter {
@@ -158,7 +158,7 @@ export function createMemoryRouter(
hydrationData: opts?.hydrationData,
routes,
mapRouteProperties,
- unstable_dataStrategy: opts?.unstable_dataStrategy,
+ dataStrategy: opts?.dataStrategy,
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
}).initialize();
}
diff --git a/packages/react-router/lib/dom-export/hydrated-router.tsx b/packages/react-router/lib/dom-export/hydrated-router.tsx
index bd7b072e5b..35e451c8c5 100644
--- a/packages/react-router/lib/dom-export/hydrated-router.tsx
+++ b/packages/react-router/lib/dom-export/hydrated-router.tsx
@@ -169,7 +169,7 @@ function createHydratedRouter(): RemixRouter {
basename: ssrInfo.context.basename,
hydrationData,
mapRouteProperties,
- unstable_dataStrategy: getSingleFetchDataStrategy(
+ dataStrategy: getSingleFetchDataStrategy(
ssrInfo.manifest,
ssrInfo.routeModules,
() => router
diff --git a/packages/react-router/lib/dom/lib.tsx b/packages/react-router/lib/dom/lib.tsx
index c6a280b2f4..f036ace794 100644
--- a/packages/react-router/lib/dom/lib.tsx
+++ b/packages/react-router/lib/dom/lib.tsx
@@ -122,7 +122,7 @@ interface DOMRouterOpts {
basename?: string;
future?: Partial;
hydrationData?: HydrationState;
- unstable_dataStrategy?: DataStrategyFunction;
+ dataStrategy?: DataStrategyFunction;
patchRoutesOnNavigation?: PatchRoutesOnNavigationFunction;
window?: Window;
}
@@ -141,7 +141,7 @@ export function createBrowserRouter(
hydrationData: opts?.hydrationData || parseHydrationData(),
routes,
mapRouteProperties,
- unstable_dataStrategy: opts?.unstable_dataStrategy,
+ dataStrategy: opts?.dataStrategy,
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
window: opts?.window,
}).initialize();
@@ -161,7 +161,7 @@ export function createHashRouter(
hydrationData: opts?.hydrationData || parseHydrationData(),
routes,
mapRouteProperties,
- unstable_dataStrategy: opts?.unstable_dataStrategy,
+ dataStrategy: opts?.dataStrategy,
patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
window: opts?.window,
}).initialize();
diff --git a/packages/react-router/lib/dom/ssr/single-fetch.tsx b/packages/react-router/lib/dom/ssr/single-fetch.tsx
index 7b93b75105..1a9d4c8f9e 100644
--- a/packages/react-router/lib/dom/ssr/single-fetch.tsx
+++ b/packages/react-router/lib/dom/ssr/single-fetch.tsx
@@ -184,7 +184,7 @@ async function singleFetchActionStrategy(
return { [actionMatch.route.id]: result };
}
- // For non-responses, proxy along the statusCode via unstable_data()
+ // For non-responses, proxy along the statusCode via data()
// (most notably for skipping action error revalidation)
return {
[actionMatch.route.id]: {
diff --git a/packages/react-router/lib/router/router.ts b/packages/react-router/lib/router/router.ts
index 202ae3090a..c016e0d7db 100644
--- a/packages/react-router/lib/router/router.ts
+++ b/packages/react-router/lib/router/router.ts
@@ -369,8 +369,8 @@ export interface RouterInit {
future?: Partial;
hydrationData?: HydrationState;
window?: Window;
+ dataStrategy?: DataStrategyFunction;
patchRoutesOnNavigation?: AgnosticPatchRoutesOnNavigationFunction;
- unstable_dataStrategy?: DataStrategyFunction;
}
/**
@@ -399,7 +399,7 @@ export interface StaticHandler {
opts?: {
requestContext?: unknown;
skipLoaderErrorBubbling?: boolean;
- unstable_dataStrategy?: DataStrategyFunction;
+ dataStrategy?: DataStrategyFunction;
}
): Promise;
queryRoute(
@@ -407,7 +407,7 @@ export interface StaticHandler {
opts?: {
routeId?: string;
requestContext?: unknown;
- unstable_dataStrategy?: DataStrategyFunction;
+ dataStrategy?: DataStrategyFunction;
}
): Promise;
}
@@ -808,7 +808,7 @@ export function createRouter(init: RouterInit): Router {
);
let inFlightDataRoutes: AgnosticDataRouteObject[] | undefined;
let basename = init.basename || "/";
- let dataStrategyImpl = init.unstable_dataStrategy || defaultDataStrategy;
+ let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
// Config driven behavior flags
@@ -3410,11 +3410,11 @@ export function createStaticHandler(
{
requestContext,
skipLoaderErrorBubbling,
- unstable_dataStrategy,
+ dataStrategy,
}: {
requestContext?: unknown;
skipLoaderErrorBubbling?: boolean;
- unstable_dataStrategy?: DataStrategyFunction;
+ dataStrategy?: DataStrategyFunction;
} = {}
): Promise {
let url = new URL(request.url);
@@ -3464,7 +3464,7 @@ export function createStaticHandler(
location,
matches,
requestContext,
- unstable_dataStrategy || null,
+ dataStrategy || null,
skipLoaderErrorBubbling === true,
null
);
@@ -3509,11 +3509,11 @@ export function createStaticHandler(
{
routeId,
requestContext,
- unstable_dataStrategy,
+ dataStrategy,
}: {
requestContext?: unknown;
routeId?: string;
- unstable_dataStrategy?: DataStrategyFunction;
+ dataStrategy?: DataStrategyFunction;
} = {}
): Promise {
let url = new URL(request.url);
@@ -3547,7 +3547,7 @@ export function createStaticHandler(
location,
matches,
requestContext,
- unstable_dataStrategy || null,
+ dataStrategy || null,
false,
match
);
@@ -3582,7 +3582,7 @@ export function createStaticHandler(
location: Location,
matches: AgnosticDataRouteMatch[],
requestContext: unknown,
- unstable_dataStrategy: DataStrategyFunction | null,
+ dataStrategy: DataStrategyFunction | null,
skipLoaderErrorBubbling: boolean,
routeMatch: AgnosticDataRouteMatch | null
): Promise | Response> {
@@ -3598,7 +3598,7 @@ export function createStaticHandler(
matches,
routeMatch || getTargetMatch(matches, location),
requestContext,
- unstable_dataStrategy,
+ dataStrategy,
skipLoaderErrorBubbling,
routeMatch != null
);
@@ -3609,7 +3609,7 @@ export function createStaticHandler(
request,
matches,
requestContext,
- unstable_dataStrategy,
+ dataStrategy,
skipLoaderErrorBubbling,
routeMatch
);
@@ -3644,7 +3644,7 @@ export function createStaticHandler(
matches: AgnosticDataRouteMatch[],
actionMatch: AgnosticDataRouteMatch,
requestContext: unknown,
- unstable_dataStrategy: DataStrategyFunction | null,
+ dataStrategy: DataStrategyFunction | null,
skipLoaderErrorBubbling: boolean,
isRouteRequest: boolean
): Promise | Response> {
@@ -3671,7 +3671,7 @@ export function createStaticHandler(
matches,
isRouteRequest,
requestContext,
- unstable_dataStrategy
+ dataStrategy
);
result = results[actionMatch.route.id];
@@ -3731,7 +3731,7 @@ export function createStaticHandler(
loaderRequest,
matches,
requestContext,
- unstable_dataStrategy,
+ dataStrategy,
skipLoaderErrorBubbling,
null,
[boundaryMatch.route.id, result]
@@ -3756,7 +3756,7 @@ export function createStaticHandler(
loaderRequest,
matches,
requestContext,
- unstable_dataStrategy,
+ dataStrategy,
skipLoaderErrorBubbling,
null
);
@@ -3778,7 +3778,7 @@ export function createStaticHandler(
request: Request,
matches: AgnosticDataRouteMatch[],
requestContext: unknown,
- unstable_dataStrategy: DataStrategyFunction | null,
+ dataStrategy: DataStrategyFunction | null,
skipLoaderErrorBubbling: boolean,
routeMatch: AgnosticDataRouteMatch | null,
pendingActionResult?: PendingActionResult
@@ -3840,7 +3840,7 @@ export function createStaticHandler(
matches,
isRouteRequest,
requestContext,
- unstable_dataStrategy
+ dataStrategy
);
if (request.signal.aborted) {
@@ -3880,10 +3880,10 @@ export function createStaticHandler(
matches: AgnosticDataRouteMatch[],
isRouteRequest: boolean,
requestContext: unknown,
- unstable_dataStrategy: DataStrategyFunction | null
+ dataStrategy: DataStrategyFunction | null
): Promise> {
let results = await callDataStrategyImpl(
- unstable_dataStrategy || defaultDataStrategy,
+ dataStrategy || defaultDataStrategy,
type,
null,
request,
@@ -4867,7 +4867,7 @@ async function convertDataStrategyResultToDataResult(
};
}
- // Convert thrown unstable_data() to ErrorResponse instances
+ // Convert thrown data() to ErrorResponse instances
result = new ErrorResponseImpl(
result.init?.status || 500,
undefined,
diff --git a/packages/react-router/lib/server-runtime/single-fetch.ts b/packages/react-router/lib/server-runtime/single-fetch.ts
index 54e216fb0f..246aa0e124 100644
--- a/packages/react-router/lib/server-runtime/single-fetch.ts
+++ b/packages/react-router/lib/server-runtime/single-fetch.ts
@@ -84,7 +84,7 @@ export async function singleFetchAction(
let result = await staticHandler.query(handlerRequest, {
requestContext: loadContext,
skipLoaderErrorBubbling: true,
- unstable_dataStrategy: getSingleFetchDataStrategy({
+ dataStrategy: getSingleFetchDataStrategy({
isActionDataRequest: true,
}),
});
@@ -172,7 +172,7 @@ export async function singleFetchLoaders(
let result = await staticHandler.query(handlerRequest, {
requestContext: loadContext,
skipLoaderErrorBubbling: true,
- unstable_dataStrategy: getSingleFetchDataStrategy({
+ dataStrategy: getSingleFetchDataStrategy({
loadRouteIds,
}),
});