Skip to content

Commit 87276ce

Browse files
committed
ref: Enable history patching by default for React Router
It's needed to follow <Link> navigation, which is pretty essential.
1 parent 2766d05 commit 87276ce

File tree

10 files changed

+33
-46
lines changed

10 files changed

+33
-46
lines changed

packages/docs/content/docs/options.mdx

+9-21
Original file line numberDiff line numberDiff line change
@@ -102,27 +102,15 @@ function Component() {
102102
This concept of _"shallow routing"_ is done via updates to the browser's
103103
[History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API/Working_with_the_History_API).
104104

105-
While the `useOptimisticSearchParams` and the adapter itself can handle shallow URL
106-
updates triggered from state updater functions, for them to react to URL changes
107-
triggered by explicit calls to the History API (either by first or third party code),
108-
you'd have to enable sync:
109-
110-
```tsx
111-
// Export available in:
112-
// 'nuqs/adapters/remix'
113-
// 'nuqs/adapters/react-router/v6'
114-
// 'nuqs/adapters/react-router/v7'
115-
// 'nuqs/adapters/react'
116-
import { enableHistorySync } from 'nuqs/adapters/remix'
117-
118-
// Somewhere top-level (like app/root.tsx)
119-
enableHistorySync()
120-
```
121-
122-
Note that you may not need this if only using your framework's router.
123-
124-
It is opt-in as it patches the History APIs, which can have side effects
125-
if third party code does it too.
105+
<Callout title="Why not using shouldRevalidate?">
106+
[`shouldRevalidate`](https://reactrouter.com/start/framework/route-module#shouldrevalidate)
107+
is the idomatic way of opting out of running loaders on navigation, but nuqs uses
108+
the opposite approach: opting in to running loaders only when needed.
109+
110+
In order to avoid specifying `shouldRevalidate` for every route, nuqs chose to
111+
patch the history methods to enable shallow routing by default (on its own updates)
112+
in React Router based frameworks.
113+
</Callout>
126114

127115
## Scroll
128116

packages/e2e/react-router/v6/src/react-router.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { enableHistorySync, NuqsAdapter } from 'nuqs/adapters/react-router/v6'
1+
import { NuqsAdapter } from 'nuqs/adapters/react-router/v6'
22
import {
33
createBrowserRouter,
44
createRoutesFromElements,
@@ -7,8 +7,6 @@ import {
77
} from 'react-router-dom'
88
import RootLayout from './layout'
99

10-
enableHistorySync()
11-
1210
// Adapt the RRv7 / Remix default export for component into a Component export for v6
1311
function load(mod: Promise<{ default: any; [otherExports: string]: any }>) {
1412
return () =>

packages/e2e/react-router/v7/app/root.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { enableHistorySync, NuqsAdapter } from 'nuqs/adapters/react-router/v7'
1+
import { NuqsAdapter } from 'nuqs/adapters/react-router/v7'
22
import {
33
isRouteErrorResponse,
44
Links,
@@ -8,8 +8,6 @@ import {
88
ScrollRestoration
99
} from 'react-router'
1010

11-
enableHistorySync()
12-
1311
import type { Route } from './+types/root'
1412

1513
export function Layout({ children }: { children: React.ReactNode }) {

packages/e2e/remix/app/root.tsx

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import { Links, Meta, Scripts, ScrollRestoration } from '@remix-run/react'
2-
import { enableHistorySync, NuqsAdapter } from 'nuqs/adapters/remix'
2+
import { NuqsAdapter } from 'nuqs/adapters/remix'
33
import RootLayout from './layout'
44

5-
enableHistorySync()
6-
75
export function Layout({ children }: { children: React.ReactNode }) {
86
return (
97
<html lang="en">

packages/nuqs/src/adapters/lib/patch-history.ts

+12
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,24 @@ export function patchHistory(
5151
if (history.nuqs?.adapters?.includes(adapter)) {
5252
return
5353
}
54+
let lastSearchSeen = typeof location === 'object' ? location.search : ''
55+
56+
emitter.on('update', search => {
57+
lastSearchSeen = search.toString()
58+
})
59+
5460
debug(
5561
'[nuqs %s] Patching history (%s adapter)',
5662
'0.0.0-inject-version-here',
5763
adapter
5864
)
5965
function sync(url: URL | string) {
66+
try {
67+
const newSearch = new URL(url, location.origin).search
68+
if (newSearch === lastSearchSeen) {
69+
return
70+
}
71+
} catch {}
6072
try {
6173
emitter.emit('update', getSearchParams(url))
6274
} catch (e) {

packages/nuqs/src/adapters/lib/react-router.ts

-3
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,6 @@ export function createReactRouterBasedAdapter(
9292
window.removeEventListener('popstate', onPopState)
9393
}
9494
}, [])
95-
useEffect(() => {
96-
emitter.emit('update', serverSearchParams)
97-
}, [serverSearchParams])
9895
return searchParams
9996
}
10097
/**

packages/nuqs/src/adapters/react-router.ts

-10
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,4 @@
11
export {
2-
/**
3-
* @deprecated This import will be removed in nuqs@3.0.0.
4-
*
5-
* Please pin your version of React Router in the import:
6-
* - `nuqs/adapters/react-router/v6`
7-
* - `nuqs/adapters/react-router/v7`.
8-
*
9-
* Note: this deprecated import (`nuqs/adapters/react-router`) is for React Router v6 only.
10-
*/
11-
enableHistorySync,
122
/**
133
* @deprecated This import will be removed in nuqs@3.0.0.
144
*

packages/nuqs/src/adapters/react-router/v6.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const {
1212
useSearchParams
1313
)
1414

15-
export { enableHistorySync, useOptimisticSearchParams }
15+
export { useOptimisticSearchParams }
1616

1717
export const NuqsAdapter = createAdapterProvider(useNuqsReactRouterV6Adapter)
18+
19+
enableHistorySync()

packages/nuqs/src/adapters/react-router/v7.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const {
1212
useSearchParams
1313
)
1414

15-
export { enableHistorySync, useOptimisticSearchParams }
15+
export { useOptimisticSearchParams }
1616

1717
export const NuqsAdapter = createAdapterProvider(useNuqsReactRouterV7Adapter)
18+
19+
enableHistorySync()

packages/nuqs/src/adapters/remix.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ const {
88
useOptimisticSearchParams
99
} = createReactRouterBasedAdapter('remix', useNavigate, useSearchParams)
1010

11-
export { enableHistorySync, useOptimisticSearchParams }
11+
export { useOptimisticSearchParams }
1212

1313
export const NuqsAdapter = createAdapterProvider(useNuqsRemixAdapter)
14+
15+
enableHistorySync()

0 commit comments

Comments
 (0)