diff --git a/packages/nuqs/src/adapters/react.ts b/packages/nuqs/src/adapters/react.ts index 33351b49..6dfaf267 100644 --- a/packages/nuqs/src/adapters/react.ts +++ b/packages/nuqs/src/adapters/react.ts @@ -1,5 +1,13 @@ import mitt from 'mitt' -import { useEffect, useState } from 'react' +import { + createContext, + createElement, + useContext, + useEffect, + useMemo, + useState, + type ReactNode +} from 'react' import { renderQueryString } from '../url-encoding' import { createAdapterProvider } from './lib/context' import type { AdapterOptions } from './lib/defs' @@ -7,16 +15,31 @@ import { patchHistory, type SearchParamsSyncEmitter } from './lib/patch-history' const emitter: SearchParamsSyncEmitter = mitt() -function updateUrl(search: URLSearchParams, options: AdapterOptions) { - const url = new URL(location.href) - url.search = renderQueryString(search) - const method = - options.history === 'push' ? history.pushState : history.replaceState - method.call(history, history.state, '', url) - emitter.emit('update', search) +function generateUpdateUrlFn(reloadPageOnShallowFalseUpdates: boolean) { + return function updateUrl(search: URLSearchParams, options: AdapterOptions) { + const url = new URL(location.href) + url.search = renderQueryString(search) + if (reloadPageOnShallowFalseUpdates && options.shallow === false) { + const method = + options.history === 'push' ? location.assign : location.replace + method.call(location, url) + } else { + const method = + options.history === 'push' ? history.pushState : history.replaceState + method.call(history, history.state, '', url) + } + emitter.emit('update', search) + } } +const NuqsReactAdapterContext = createContext({ + reloadPageOnShallowFalseUpdates: false +}) + function useNuqsReactAdapter() { + const { reloadPageOnShallowFalseUpdates } = useContext( + NuqsReactAdapterContext + ) const [searchParams, setSearchParams] = useState(() => { if (typeof location === 'undefined') { return new URLSearchParams() @@ -36,13 +59,31 @@ function useNuqsReactAdapter() { window.removeEventListener('popstate', onPopState) } }, []) + const updateUrl = useMemo( + () => generateUpdateUrlFn(reloadPageOnShallowFalseUpdates), + [reloadPageOnShallowFalseUpdates] + ) return { searchParams, updateUrl } } -export const NuqsAdapter = createAdapterProvider(useNuqsReactAdapter) +const NuqsReactAdapter = createAdapterProvider(useNuqsReactAdapter) + +export function NuqsAdapter({ + children, + reloadPageOnShallowFalseUpdates = false +}: { + children: ReactNode + reloadPageOnShallowFalseUpdates?: boolean +}) { + return createElement( + NuqsReactAdapterContext.Provider, + { value: { reloadPageOnShallowFalseUpdates } }, + createElement(NuqsReactAdapter, null, children) + ) +} /** * Opt-in to syncing shallow updates of the URL with the useOptimisticSearchParams hook.