Skip to content

Commit

Permalink
Add deprecation warnings for v7 flags in v6 (#11750)
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 authored Oct 18, 2024
1 parent 50c59ea commit caa0895
Show file tree
Hide file tree
Showing 13 changed files with 155 additions and 11 deletions.
9 changes: 9 additions & 0 deletions .changeset/ninety-queens-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"react-router-dom": minor
"react-router": minor
"@remix-run/router": minor
---

- Log deprecation warnings for v7 flags
- Add deprecation warnings to `json`/`defer` in favor of returning raw objects
- These methods will be removed in React Router v7
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,16 @@
"none": "58.1 kB"
},
"packages/react-router/dist/react-router.production.min.js": {
"none": "15.0 kB"
"none": "16.5 kB"
},
"packages/react-router/dist/umd/react-router.production.min.js": {
"none": "17.5 kB"
"none": "19.0 kB"
},
"packages/react-router-dom/dist/react-router-dom.production.min.js": {
"none": "17.3 kB"
"none": "17.5 kB"
},
"packages/react-router-dom/dist/umd/react-router-dom.production.min.js": {
"none": "23.8 kB"
"none": "24.0 kB"
}
},
"pnpm": {
Expand Down
1 change: 1 addition & 0 deletions packages/react-router-dom/__tests__/exports-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as ReactRouter from "react-router";
import * as ReactRouterDOM from "react-router-dom";

let nonReExportedKeys = new Set([
"UNSAFE_logV6DeprecationWarnings",
"UNSAFE_mapRouteProperties",
"UNSAFE_useRoutesImpl",
]);
Expand Down
16 changes: 14 additions & 2 deletions packages/react-router-dom/__tests__/scroll-restoration-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,21 @@ describe(`ScrollRestoration`, () => {
children: testPages,
},
],
{ basename: "/base", window: testWindow }
{
basename: "/base",
window: testWindow,
future: {
v7_fetcherPersist: true,
v7_normalizeFormMethod: true,
v7_partialHydration: true,
v7_skipActionErrorRevalidation: true,
v7_relativeSplatPath: true,
},
}
);
let { container } = render(
<RouterProvider router={router} future={{ v7_startTransition: true }} />
);
let { container } = render(<RouterProvider router={router} />);

expect(getHtml(container)).toMatch("On page 1");

Expand Down
12 changes: 12 additions & 0 deletions packages/react-router-dom/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
UNSAFE_DataRouterStateContext as DataRouterStateContext,
UNSAFE_NavigationContext as NavigationContext,
UNSAFE_RouteContext as RouteContext,
UNSAFE_logV6DeprecationWarnings as logV6DeprecationWarnings,
UNSAFE_mapRouteProperties as mapRouteProperties,
UNSAFE_useRouteId as useRouteId,
UNSAFE_useRoutesImpl as useRoutesImpl,
Expand Down Expand Up @@ -716,6 +717,11 @@ export function RouterProvider({
[router.future.v7_relativeSplatPath]
);

React.useEffect(
() => logV6DeprecationWarnings(future, router.future),
[future, router.future]
);

// The fragment and {null} here are important! We need them to keep React 18's
// useId happy when we are server-rendering since we may have a <script> here
// containing the hydrated server-side staticContext (from StaticRouterProvider).
Expand Down Expand Up @@ -807,6 +813,8 @@ export function BrowserRouter({

React.useLayoutEffect(() => history.listen(setState), [history, setState]);

React.useEffect(() => logV6DeprecationWarnings(future), [future]);

return (
<Router
basename={basename}
Expand Down Expand Up @@ -858,6 +866,8 @@ export function HashRouter({

React.useLayoutEffect(() => history.listen(setState), [history, setState]);

React.useEffect(() => logV6DeprecationWarnings(future), [future]);

return (
<Router
basename={basename}
Expand Down Expand Up @@ -905,6 +915,8 @@ function HistoryRouter({

React.useLayoutEffect(() => history.listen(setState), [history, setState]);

React.useEffect(() => logV6DeprecationWarnings(future), [future]);

return (
<Router
basename={basename}
Expand Down
1 change: 1 addition & 0 deletions packages/react-router-native/__tests__/exports-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as ReactRouter from "react-router";
import * as ReactRouterNative from "react-router-native";

let nonReExportedKeys = new Set([
"UNSAFE_logV6DeprecationWarnings",
"UNSAFE_mapRouteProperties",
"UNSAFE_useRoutesImpl",
"UNSAFE_ViewTransitionContext",
Expand Down
6 changes: 5 additions & 1 deletion packages/react-router/__tests__/Router-basename-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@ describe("<Router basename>", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter basename="/app" initialEntries={["/home"]}>
<MemoryRouter
basename="/app"
initialEntries={["/home"]}
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<Routes>
<Route path="/" element={<h1>App</h1>} />
</Routes>
Expand Down
4 changes: 3 additions & 1 deletion packages/react-router/__tests__/Routes-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ describe("<Routes>", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter>
<MemoryRouter
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<Routes />
</MemoryRouter>
);
Expand Down
15 changes: 12 additions & 3 deletions packages/react-router/__tests__/descendant-routes-warning-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ describe("Descendant <Routes>", () => {

TestRenderer.act(() => {
TestRenderer.create(
<MemoryRouter initialEntries={["/courses/react"]}>
<MemoryRouter
initialEntries={["/courses/react"]}
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<Routes>
<Route path="courses" element={<Courses />}>
<Route path="react" element={<ReactCourses />} />
Expand Down Expand Up @@ -79,7 +82,10 @@ Please change the parent <Route path="react"> to <Route path="react/*">.`);

TestRenderer.act(() => {
TestRenderer.create(
<MemoryRouter initialEntries={["/"]}>
<MemoryRouter
initialEntries={["/"]}
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<Routes>
<Route path="/" element={<ReactCourses />} />
</Routes>
Expand Down Expand Up @@ -124,7 +130,10 @@ Please change the parent <Route path="/"> to <Route path="*">.`);

TestRenderer.act(() => {
TestRenderer.create(
<MemoryRouter initialEntries={["/courses/react"]}>
<MemoryRouter
initialEntries={["/courses/react"]}
future={{ v7_startTransition: true, v7_relativeSplatPath: true }}
>
<Routes>
<Route path="courses" element={<Courses />}>
<Route path="react/*" element={<ReactCourses />} />
Expand Down
2 changes: 2 additions & 0 deletions packages/react-router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ import {
useRoutes,
useRoutesImpl,
} from "./lib/hooks";
import { logV6DeprecationWarnings } from "./lib/deprecations";

// Exported for backwards compatibility, but not being used internally anymore
type Hash = string;
Expand Down Expand Up @@ -351,4 +352,5 @@ export {
mapRouteProperties as UNSAFE_mapRouteProperties,
useRouteId as UNSAFE_useRouteId,
useRoutesImpl as UNSAFE_useRoutesImpl,
logV6DeprecationWarnings as UNSAFE_logV6DeprecationWarnings,
};
8 changes: 8 additions & 0 deletions packages/react-router/lib/components.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import {
useRoutes,
useRoutesImpl,
} from "./hooks";
import { logV6DeprecationWarnings } from "./deprecations";

export interface FutureConfig {
v7_relativeSplatPath: boolean;
Expand Down Expand Up @@ -154,6 +155,11 @@ export function RouterProvider({
[router, navigator, basename]
);

React.useEffect(
() => logV6DeprecationWarnings(future, router.future),
[router, future]
);

// The fragment and {null} here are important! We need them to keep React 18's
// useId happy when we are server-rendering since we may have a <script> here
// containing the hydrated server-side staticContext (from StaticRouterProvider).
Expand Down Expand Up @@ -248,6 +254,8 @@ export function MemoryRouter({

React.useLayoutEffect(() => history.listen(setState), [history, setState]);

React.useEffect(() => logV6DeprecationWarnings(future), [future]);

return (
<Router
basename={basename}
Expand Down
77 changes: 77 additions & 0 deletions packages/react-router/lib/deprecations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import type { FutureConfig as RouterFutureConfig } from "@remix-run/router";
import type { FutureConfig as RenderFutureConfig } from "./components";

const alreadyWarned: { [key: string]: boolean } = {};

export function warnOnce(key: string, message: string): void {
if (!alreadyWarned[message]) {
alreadyWarned[message] = true;
console.warn(message);
}
}

const logDeprecation = (flag: string, msg: string, link: string) =>
warnOnce(
flag,
`⚠️ React Router Future Flag Warning: ${msg}. ` +
`You can use the \`${flag}\` future flag to opt-in early. ` +
`For more information, see ${link}.`
);

export function logV6DeprecationWarnings(
renderFuture: Partial<RenderFutureConfig> | undefined,
routerFuture?: Omit<RouterFutureConfig, "v7_prependBasename">
) {
if (!renderFuture?.v7_startTransition) {
logDeprecation(
"v7_startTransition",
"React Router will begin wrapping state updates in `React.startTransition` in v7",
"https://reactrouter.com/v6/upgrading/future#v7_starttransition"
);
}

if (
!renderFuture?.v7_relativeSplatPath &&
(!routerFuture || !routerFuture.v7_relativeSplatPath)
) {
logDeprecation(
"v7_relativeSplatPath",
"Relative route resolution within Splat routes is changing in v7",
"https://reactrouter.com/v6/upgrading/future#v7_relativesplatpath"
);
}

if (routerFuture) {
if (!routerFuture.v7_fetcherPersist) {
logDeprecation(
"v7_fetcherPersist",
"The persistence behavior of fetchers is changing in v7",
"https://reactrouter.com/v6/upgrading/future#v7_fetcherpersist"
);
}

if (!routerFuture.v7_normalizeFormMethod) {
logDeprecation(
"v7_normalizeFormMethod",
"Casing of `formMethod` fields is being normalized to uppercase in v7",
"https://reactrouter.com/v6/upgrading/future#v7_normalizeformmethod"
);
}

if (!routerFuture.v7_partialHydration) {
logDeprecation(
"v7_partialHydration",
"`RouterProvider` hydration behavior is changing in v7",
"https://reactrouter.com/v6/upgrading/future#v7_partialhydration"
);
}

if (!routerFuture.v7_skipActionErrorRevalidation) {
logDeprecation(
"v7_skipActionErrorRevalidation",
"The revalidation behavior after 4xx/5xx `action` responses is changing in v7",
"https://reactrouter.com/v6/upgrading/future#v7_skipactionerrorrevalidation"
);
}
}
}
7 changes: 7 additions & 0 deletions packages/router/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1366,6 +1366,9 @@ export type JsonFunction = <Data>(
/**
* This is a shortcut for creating `application/json` responses. Converts `data`
* to JSON and sets the `Content-Type` header.
*
* @deprecated The `json` method is deprecated in favor of returning raw objects.
* This method will be removed in v7.
*/
export const json: JsonFunction = (data, init = {}) => {
let responseInit = typeof init === "number" ? { status: init } : init;
Expand Down Expand Up @@ -1604,6 +1607,10 @@ export type DeferFunction = (
init?: number | ResponseInit
) => DeferredData;

/**
* @deprecated The `defer` method is deprecated in favor of returning raw
* objects. This method will be removed in v7.
*/
export const defer: DeferFunction = (data, init = {}) => {
let responseInit = typeof init === "number" ? { status: init } : init;

Expand Down

0 comments on commit caa0895

Please sign in to comment.