Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add deprecation warnings for v7 flags in v6 #11750

Merged
merged 16 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
brophdawg11 marked this conversation as resolved.
Show resolved Hide resolved
"@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