Skip to content

Commit 94486c2

Browse files
franky47ahmedrowaihi
authored andcommitted
chore: Narrow the scope of implementation
- Use a scoped location subscribing only to search params updates - Use the useNavigate hook for navigation (don't need the whole router) - Handle native search params arrays (for later) - Add comments to keep track of why we made these choices
1 parent 4fbea7a commit 94486c2

File tree

1 file changed

+36
-22
lines changed

1 file changed

+36
-22
lines changed
+36-22
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,59 @@
1-
import { useRouter, useRouterState } from '@tanstack/react-router'
1+
import { useLocation, useNavigate } from '@tanstack/react-router'
22
import { startTransition, useCallback, useMemo } from 'react'
3+
import { renderQueryString } from '../url-encoding'
34
import { createAdapterProvider } from './lib/context'
45
import type { AdapterInterface, UpdateUrlFunction } from './lib/defs'
56

67
function useNuqsTanstackRouterAdapter(): AdapterInterface {
7-
const state = useRouterState()
8-
const router = useRouter()
9-
10-
const search = useMemo(
11-
() => new URLSearchParams(state.location.search || ''),
12-
[state.location.search]
8+
const search = useLocation({ select: state => state.search })
9+
const navigate = useNavigate()
10+
const searchParams = useMemo(
11+
() =>
12+
// search is a Record<string, string | string[]>,
13+
// so we need to flatten it into a list of key/value pairs,
14+
// replicating keys that have multiple values before passing it
15+
// to URLSearchParams, otherwise { foo: ['bar', 'baz'] }
16+
// ends up as { foo → 'bar,baz' } instead of { foo → 'bar', foo → 'baz' }
17+
new URLSearchParams(
18+
Object.entries(search).flatMap(([key, value]) => {
19+
if (Array.isArray(value)) {
20+
return value.map(v => [key, v])
21+
} else {
22+
return [[key, value]]
23+
}
24+
})
25+
),
26+
[search]
1327
)
1428

1529
const updateUrl: UpdateUrlFunction = useCallback(
1630
(search, options) => {
31+
// Wrapping in a startTransition seems to be necessary
32+
// to support scroll restoration
1733
startTransition(() => {
18-
const url = renderURL(location.pathname, search)
19-
router.navigate({
20-
from: state.location.pathname,
21-
to: url,
22-
search: search,
34+
navigate({
35+
// I know the docs say to use `search` here, but it would require
36+
// userland code to stitch the nuqs definitions to the route declarations
37+
// in order for TSR to serialize them, which kind of breaks the
38+
// "works out of the box" promise, and it also wouldn't support
39+
// the custom URL encoding.
40+
// TBC if it causes issues with consuming those search params
41+
// in other parts of the app.
42+
to: renderQueryString(search),
2343
replace: options.history === 'replace',
24-
resetScroll: options.scroll
44+
resetScroll: options.scroll,
45+
hash: prevHash => prevHash ?? ''
2546
})
2647
})
2748
},
28-
[router.navigate]
49+
[navigate]
2950
)
3051

3152
return {
32-
searchParams: search,
53+
searchParams,
3354
updateUrl,
3455
rateLimitFactor: 1
3556
}
3657
}
3758

38-
function renderURL(pathname: string, search: URLSearchParams) {
39-
const hashlessBase = pathname.split('#')[0] ?? ''
40-
const query = search.toString() ? `?${search.toString()}` : ''
41-
const hash = location.hash
42-
return hashlessBase + query + hash
43-
}
44-
4559
export const NuqsAdapter = createAdapterProvider(useNuqsTanstackRouterAdapter)

0 commit comments

Comments
 (0)