Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions .changeset/thin-nails-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"react-router": minor
---

Remove duplicate `RouterProvider` impliementations
10 changes: 2 additions & 8 deletions packages/react-router/__tests__/data-memory-router-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import urlDataStrategy from "./router/utils/urlDataStrategy";
import { createDeferred } from "./router/utils/utils";
import MemoryNavigate from "./utils/MemoryNavigate";
import getHtml from "./utils/getHtml";
import { RouterProvider as DomRouterProvider } from "../lib/dom/lib";

describe("createMemoryRouter", () => {
let consoleWarn: jest.SpyInstance;
Expand Down Expand Up @@ -1193,9 +1192,7 @@ describe("createMemoryRouter", () => {
},
]);

// TODO: Fetchers only supported in DomRouterProvider at the moment, but
// that should be fixed once we align the two
render(<DomRouterProvider router={router} />);
render(<RouterProvider router={router} />);

await waitFor(() => screen.getByText("Fetch (1, empty)"));
fireEvent.click(screen.getByText("Fetch (1, empty)"));
Expand Down Expand Up @@ -1251,9 +1248,7 @@ describe("createMemoryRouter", () => {
},
]);

// TODO: Fetchers only supported in DomRouterProvider at the moment, but
// that should be fixed once we align the two
render(<DomRouterProvider router={router} />);
render(<RouterProvider router={router} />);

await waitFor(() => screen.getByText("Fetch (1, empty)"));
fireEvent.click(screen.getByText("Fetch (1, empty)"));
Expand Down Expand Up @@ -3371,7 +3366,6 @@ describe("createMemoryRouter", () => {
</React.Suspense>
);

console.log(getHtml(container));
expect(getHtml(container)).toMatchInlineSnapshot(`
"<div>
<p>
Expand Down
182 changes: 182 additions & 0 deletions packages/react-router/__tests__/data-router-no-dom-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
/**
* @jest-environment node
*/

import * as React from "react";
import renderer from "react-test-renderer";
import { RouterProvider } from "../lib/dom/lib";
import { createMemoryRouter } from "../lib/components";
import { useLoaderData, useNavigate } from "../lib/hooks";

describe("RouterProvider works when no DOM APIs are available", () => {
it("renders and navigates", async () => {
let router = createMemoryRouter([
{
path: "/",
Component: () => {
let navigate = useNavigate();
return <button onClick={() => navigate("/foo")}>Go to /foo</button>;
},
},
{
path: "/foo",
loader: () => "FOO",
Component: () => {
let data = useLoaderData() as string;
return <h1>{data}</h1>;
},
},
]);
const component = renderer.create(<RouterProvider router={router} />);
let tree = component.toJSON();
expect(tree).toMatchInlineSnapshot(`
<button
onClick={[Function]}
>
Go to /foo
</button>
`);

await renderer.act(async () => {
// @ts-expect-error
tree.props.onClick();
await new Promise((resolve) => setTimeout(resolve, 0));
});

tree = component.toJSON();
expect(tree).toMatchInlineSnapshot(`
<h1>
FOO
</h1>
`);
});

it("is defensive against a view transition navigation", async () => {
let router = createMemoryRouter([
{
path: "/",
Component: () => {
let navigate = useNavigate();
return <button onClick={() => navigate("/foo")}>Go to /foo</button>;
},
},
{
path: "/foo",
loader: () => "FOO",
Component: () => {
let data = useLoaderData() as string;
return <h1>{data}</h1>;
},
},
]);
const component = renderer.create(<RouterProvider router={router} />);
let tree = component.toJSON();
expect(tree).toMatchInlineSnapshot(`
<button
onClick={[Function]}
>
Go to /foo
</button>
`);

let spy = jest.fn();
let unsubscribe = router.subscribe(spy);

await renderer.act(async () => {
router.navigate("/foo", {
unstable_viewTransition: true,
});
await new Promise((resolve) => setTimeout(resolve, 0));
});

tree = component.toJSON();
expect(tree).toMatchInlineSnapshot(`
<h1>
FOO
</h1>
`);

expect(spy.mock.calls[0][0].location.pathname).toBe("/");
expect(spy.mock.calls[0][0].navigation.state).toBe("loading");
expect(spy.mock.calls[0][0].navigation.location.pathname).toBe("/foo");
expect(spy.mock.calls[0][1].unstable_viewTransitionOpts).toBeUndefined();

expect(spy.mock.calls[1][0].location.pathname).toBe("/foo");
expect(spy.mock.calls[1][0].navigation.state).toBe("idle");
expect(spy.mock.calls[1][1].unstable_viewTransitionOpts).toEqual({
currentLocation: {
hash: "",
key: "default",
pathname: "/",
search: "",
state: null,
},
nextLocation: {
hash: "",
key: expect.any(String),
pathname: "/foo",
search: "",
state: null,
},
});

unsubscribe();
});

it("is defensive against a flushSync navigation", async () => {
let router = createMemoryRouter([
{
path: "/",
Component: () => {
let navigate = useNavigate();
return <button onClick={() => navigate("/foo")}>Go to /foo</button>;
},
},
{
path: "/foo",
loader: () => "FOO",
Component: () => {
let data = useLoaderData() as string;
return <h1>{data}</h1>;
},
},
]);
const component = renderer.create(<RouterProvider router={router} />);
let tree = component.toJSON();
expect(tree).toMatchInlineSnapshot(`
<button
onClick={[Function]}
>
Go to /foo
</button>
`);

let spy = jest.fn();
let unsubscribe = router.subscribe(spy);

await renderer.act(async () => {
router.navigate("/foo", {
unstable_flushSync: true,
});
await new Promise((resolve) => setTimeout(resolve, 0));
});

tree = component.toJSON();
expect(tree).toMatchInlineSnapshot(`
<h1>
FOO
</h1>
`);

expect(spy.mock.calls[0][0].location.pathname).toBe("/");
expect(spy.mock.calls[0][0].navigation.state).toBe("loading");
expect(spy.mock.calls[0][0].navigation.location.pathname).toBe("/foo");
expect(spy.mock.calls[0][1].unstable_flushSync).toBe(true);

expect(spy.mock.calls[1][0].location.pathname).toBe("/foo");
expect(spy.mock.calls[1][0].navigation.state).toBe("idle");
expect(spy.mock.calls[1][1].unstable_flushSync).toBe(false);

unsubscribe();
});
});
6 changes: 2 additions & 4 deletions packages/react-router/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ import type {
PathRouteProps,
RouteProps,
RouterProps,
RouterProviderProps,
RoutesProps,
} from "./lib/components";
import {
Expand All @@ -67,7 +66,6 @@ import {
Outlet,
Route,
Router,
RouterProvider,
Routes,
createRoutesFromChildren,
renderMatches,
Expand Down Expand Up @@ -168,7 +166,6 @@ export type {
RouteObject,
RouteProps,
RouterProps,
RouterProviderProps,
RoutesProps,
Search,
ShouldRevalidateFunction,
Expand All @@ -188,7 +185,6 @@ export {
Outlet,
Route,
Router,
RouterProvider,
Routes,
createMemoryRouter,
createPath,
Expand Down Expand Up @@ -279,6 +275,7 @@ export type {
SubmitFunction,
FetcherSubmitFunction,
FetcherWithComponents,
RouterProviderProps,
} from "./lib/dom/lib";
export {
createBrowserRouter,
Expand All @@ -293,6 +290,7 @@ export {
unstable_HistoryRouter,
NavLink,
Form,
RouterProvider,
ScrollRestoration,
useLinkClickHandler,
useSearchParams,
Expand Down
Loading