Skip to content

Commit 016f780

Browse files
authored
fix: handle reading location from data router #233 (#258)
1 parent eef4610 commit 016f780

File tree

8 files changed

+330
-43
lines changed

8 files changed

+330
-43
lines changed

.vscode/launch.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
3+
"version": "0.2.0",
4+
"configurations": [
5+
{
6+
"type": "node",
7+
"request": "launch",
8+
"name": "Debug Current Test File",
9+
"autoAttachChildProcesses": true,
10+
"skipFiles": ["<node_internals>/**", "**/node_modules/**"],
11+
"program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
12+
"args": ["run", "--root", "packages/use-query-params-adapter-react-router-6", "${relativeFile}"],
13+
"smartStep": true,
14+
"console": "integratedTerminal",
15+
"runtimeExecutable": "/usr/bin/env node"
16+
}
17+
]
18+
}

packages/use-query-params-adapter-react-router-6/package.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,20 @@
2727
"author": "Peter Beshai <peter.beshai@gmail.com>",
2828
"license": "ISC",
2929
"devDependencies": {
30-
"react-router": ">=6",
31-
"react-router-dom": ">=6",
30+
"@remix-run/router": "^1.3.2",
31+
"@remix-run/web-fetch": "^4.3.2",
3232
"history": "^5.2.0",
3333
"lint-staged": "^10.5.4",
3434
"prettier": "^2.2.1",
3535
"react": "^17.0.2",
36-
"react-dom": "^17.0.2"
36+
"react-dom": "^17.0.2",
37+
"react-router": "^6.8.1",
38+
"react-router-dom": "^6.8.1"
3739
},
3840
"peerDependencies": {
3941
"react": ">=16.8.0",
4042
"react-dom": ">=16.8.0",
41-
"react-router": ">=6"
42-
43+
"react-router": "^6.8.1"
4344
},
4445
"dependencies": {
4546
"use-query-params": "file:../use-query-params"

packages/use-query-params-adapter-react-router-6/src/__tests__/react-router-6.test.tsx

Lines changed: 70 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,85 @@
11
import { cleanup, render } from '@testing-library/react';
2-
import { createMemoryHistory } from 'history';
32
import * as React from 'react';
4-
import { unstable_HistoryRouter } from 'react-router-dom';
5-
import { describe, afterEach } from 'vitest';
6-
import { QueryParamProvider, QueryParamOptions } from 'use-query-params/src';
3+
import { createMemoryRouter, RouterProvider } from 'react-router-dom';
4+
import { QueryParamOptions, QueryParamProvider } from 'use-query-params/src';
75
import { testSpec } from 'use-query-params/src/__tests__/routers/shared';
6+
import { afterEach, describe, vi } from 'vitest';
87
import { ReactRouter6Adapter } from '..';
98

10-
// use this router so we can pass our own history to inspect
11-
const HistoryRouter = unstable_HistoryRouter;
12-
139
function renderWithRouter(
1410
ui: React.ReactNode,
1511
initialRoute: string,
1612
options?: QueryParamOptions
1713
) {
18-
const history = createMemoryHistory({ initialEntries: [initialRoute] });
19-
const results = render(
20-
<HistoryRouter history={history}>
21-
<QueryParamProvider adapter={ReactRouter6Adapter} options={options}>
22-
{ui}
23-
</QueryParamProvider>
24-
</HistoryRouter>
14+
// note this set up is a bit weird due to historical reasons where
15+
// we originally relied on a history object for a router to
16+
// determine push/replace. this is less the focus of newer react
17+
// router versions, but this adapter approach works.
18+
let entries: any[] = [initialRoute];
19+
const router = createMemoryRouter(
20+
[
21+
{
22+
path: '/:page?',
23+
element: (
24+
<QueryParamProvider adapter={ReactRouter6Adapter} options={options}>
25+
{ui}
26+
</QueryParamProvider>
27+
),
28+
},
29+
],
30+
{ initialEntries: entries }
2531
);
26-
const rerender = (ui: React.ReactNode, newOptions = options) =>
27-
results.rerender(
28-
<HistoryRouter history={history}>
29-
<QueryParamProvider adapter={ReactRouter6Adapter} options={newOptions}>
30-
{ui}
31-
</QueryParamProvider>
32-
</HistoryRouter>
32+
let history = {
33+
router,
34+
get location() {
35+
return this.router.state.location;
36+
},
37+
replace: vi.fn(),
38+
push: vi.fn(),
39+
};
40+
41+
// keep track of updates to help tests inspect push/replace/rerender
42+
router.subscribe(function (state) {
43+
entries.push(state.location);
44+
if (state.historyAction === 'REPLACE') {
45+
history.replace(state.location);
46+
} else if (state.historyAction === 'PUSH') {
47+
history.push(state.location);
48+
}
49+
});
50+
51+
const results = render(<RouterProvider router={router} />);
52+
const rerender = (ui: React.ReactNode, newOptions = options) => {
53+
const newRouter = createMemoryRouter(
54+
[
55+
{
56+
path: '/:page?',
57+
element: (
58+
<QueryParamProvider
59+
adapter={ReactRouter6Adapter}
60+
options={newOptions}
61+
>
62+
{ui}
63+
</QueryParamProvider>
64+
),
65+
},
66+
],
67+
{ initialEntries: entries }
3368
);
69+
history.router = newRouter;
70+
71+
// keep track of updates to help tests inspect push/replace/rerender
72+
newRouter.subscribe(function (state) {
73+
entries.push(state.location);
74+
if (state.historyAction === 'REPLACE') {
75+
history.replace(state.location);
76+
} else if (state.historyAction === 'PUSH') {
77+
history.push(state.location);
78+
}
79+
});
80+
81+
return results.rerender(<RouterProvider router={newRouter} />);
82+
};
3483
return {
3584
...results,
3685
rerender,

packages/use-query-params-adapter-react-router-6/src/__tests__/setupTests.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,24 @@
33
// expect(element).toHaveTextContent(/react/i)
44
// learn more: https://github.com/testing-library/jest-dom
55
import '@testing-library/jest-dom/extend-expect';
6+
import { fetch, Request, Response } from '@remix-run/web-fetch';
7+
8+
// https://stackoverflow.com/a/74501698/14056107
9+
// prevent Request not being defined in Vitest
10+
if (!globalThis.fetch) {
11+
// Built-in lib.dom.d.ts expects `fetch(Request | string, ...)` but the web
12+
// fetch API allows a URL so @remix-run/web-fetch defines
13+
// `fetch(string | URL | Request, ...)`
14+
// @ts-expect-error
15+
globalThis.fetch = fetch;
16+
}
17+
if (!globalThis.Request) {
18+
// Same as above, lib.dom.d.ts doesn't allow a URL to the Request constructor
19+
// @ts-expect-error
20+
globalThis.Request = Request;
21+
}
22+
if (!globalThis.Response) {
23+
// web-std/fetch Response does not currently implement Response.error()
24+
// @ts-expect-error
25+
globalThis.Response = Response;
26+
}

packages/use-query-params-adapter-react-router-6/src/index.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { useContext } from 'react';
2-
import { UNSAFE_NavigationContext, useNavigate, useLocation } from 'react-router-dom';
2+
import {
3+
UNSAFE_NavigationContext,
4+
useNavigate,
5+
useLocation,
6+
UNSAFE_DataRouterContext,
7+
} from 'react-router-dom';
38
import {
49
QueryParamAdapter,
510
QueryParamAdapterComponent,
@@ -18,6 +23,7 @@ export const ReactRouter6Adapter: QueryParamAdapterComponent = ({
1823
// see: https://github.com/remix-run/react-router/blob/f3d87dcc91fbd6fd646064b88b4be52c15114603/packages/react-router-dom/index.tsx#L113-L131
1924
const { navigator } = useContext(UNSAFE_NavigationContext);
2025
const navigate = useNavigate();
26+
const router = useContext(UNSAFE_DataRouterContext)?.router;
2127
const location = useLocation();
2228

2329
const adapter: QueryParamAdapter = {
@@ -35,7 +41,9 @@ export const ReactRouter6Adapter: QueryParamAdapterComponent = ({
3541
},
3642
get location() {
3743
// be a bit defensive here in case of an unexpected breaking change in React Router
38-
return (navigator as any)?.location ?? location;
44+
return (
45+
router?.state?.location ?? (navigator as any)?.location ?? location
46+
);
3947
},
4048
};
4149

packages/use-query-params/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@
6363
"react": "^17.0.2",
6464
"react-dom": "^17.0.2",
6565
"react-router-5": "npm:react-router@^5.3.3",
66-
"react-router-6": "npm:react-router@^6.3.0",
66+
"react-router-6": "npm:react-router@^6.8.1",
6767
"react-router-dom-5": "npm:react-router-dom@^5.3.3",
68-
"react-router-dom-6": "npm:react-router-dom@^6.3.0"
68+
"react-router-dom-6": "npm:react-router-dom@^6.8.1"
6969
},
7070
"peerDependencies": {
7171
"react": ">=16.8.0",

packages/use-query-params/src/__tests__/setupTests.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,24 @@
33
// expect(element).toHaveTextContent(/react/i)
44
// learn more: https://github.com/testing-library/jest-dom
55
import '@testing-library/jest-dom/extend-expect';
6+
import { fetch, Request, Response } from '@remix-run/web-fetch';
7+
8+
// https://stackoverflow.com/a/74501698/14056107
9+
// prevent Request not being defined in Vitest
10+
if (!globalThis.fetch) {
11+
// Built-in lib.dom.d.ts expects `fetch(Request | string, ...)` but the web
12+
// fetch API allows a URL so @remix-run/web-fetch defines
13+
// `fetch(string | URL | Request, ...)`
14+
// @ts-expect-error
15+
globalThis.fetch = fetch;
16+
}
17+
if (!globalThis.Request) {
18+
// Same as above, lib.dom.d.ts doesn't allow a URL to the Request constructor
19+
// @ts-expect-error
20+
globalThis.Request = Request;
21+
}
22+
if (!globalThis.Response) {
23+
// web-std/fetch Response does not currently implement Response.error()
24+
// @ts-expect-error
25+
globalThis.Response = Response;
26+
}

0 commit comments

Comments
 (0)