diff --git a/packages/next/client/components/app-router.tsx b/packages/next/client/components/app-router.tsx
index e0b2c964911f..a1ed740d1094 100644
--- a/packages/next/client/components/app-router.tsx
+++ b/packages/next/client/components/app-router.tsx
@@ -26,7 +26,7 @@ import {
// ParamsContext,
PathnameContext,
// LayoutSegmentsContext,
-} from './hooks-client-context'
+} from '../../shared/lib/hooks-client-context'
import { useReducerWithReduxDevtools } from './use-reducer-with-devtools'
import { ErrorBoundary, GlobalErrorComponent } from './error-boundary'
diff --git a/packages/next/client/components/navigation.ts b/packages/next/client/components/navigation.ts
index f12b6d793ade..39b3d7092521 100644
--- a/packages/next/client/components/navigation.ts
+++ b/packages/next/client/components/navigation.ts
@@ -11,7 +11,7 @@ import {
// ParamsContext,
PathnameContext,
// LayoutSegmentsContext,
-} from './hooks-client-context'
+} from '../../shared/lib/hooks-client-context'
import { staticGenerationBailout } from './static-generation-bailout'
const INTERNAL_URLSEARCHPARAMS_INSTANCE = Symbol(
diff --git a/packages/next/client/index.tsx b/packages/next/client/index.tsx
index f9ec72ae7ca3..c64007f847db 100644
--- a/packages/next/client/index.tsx
+++ b/packages/next/client/index.tsx
@@ -35,7 +35,15 @@ import { ImageConfigComplete } from '../shared/lib/image-config'
import { removeBasePath } from './remove-base-path'
import { hasBasePath } from './has-base-path'
import { AppRouterContext } from '../shared/lib/app-router-context'
-import { adaptForAppRouterInstance } from '../shared/lib/router/adapters'
+import {
+ adaptForAppRouterInstance,
+ adaptForPathname,
+ adaptForSearchParams,
+} from '../shared/lib/router/adapters'
+import {
+ PathnameContext,
+ SearchParamsContext,
+} from '../shared/lib/hooks-client-context'
const ReactDOM = process.env.__NEXT_REACT_ROOT
? require('react-dom/client')
@@ -309,17 +317,21 @@ function AppContainer({
}
>
-
-
-
- {children}
-
-
-
+
+
+
+
+
+ {children}
+
+
+
+
+
)
diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx
index 5b08c664f1f8..d0fce3954e70 100644
--- a/packages/next/server/render.tsx
+++ b/packages/next/server/render.tsx
@@ -82,8 +82,16 @@ import { ImageConfigContext } from '../shared/lib/image-config-context'
import stripAnsi from 'next/dist/compiled/strip-ansi'
import { shouldUseReactRoot } from './utils'
import { stripInternalQueries } from './internal-utils'
-import { adaptForAppRouterInstance } from '../shared/lib/router/adapters'
+import {
+ adaptForAppRouterInstance,
+ adaptForPathname,
+ adaptForSearchParams,
+} from '../shared/lib/router/adapters'
import { AppRouterContext } from '../shared/lib/app-router-context'
+import {
+ PathnameContext,
+ SearchParamsContext,
+} from '../shared/lib/hooks-client-context'
let tryGetPreviewData: typeof import('./api-utils/node').tryGetPreviewData
let warn: typeof import('../build/output/log').warn
@@ -645,32 +653,36 @@ export async function renderToHTML(
const AppContainer = ({ children }: { children: JSX.Element }) => (
-
-
- {
- head = state
- },
- updateScripts: (scripts) => {
- scriptLoader = scripts
- },
- scripts: initialScripts,
- mountedInstances: new Set(),
- }}
- >
- reactLoadableModules.push(moduleName)}
- >
-
-
- {children}
-
-
-
-
-
-
+
+
+
+
+ {
+ head = state
+ },
+ updateScripts: (scripts) => {
+ scriptLoader = scripts
+ },
+ scripts: initialScripts,
+ mountedInstances: new Set(),
+ }}
+ >
+ reactLoadableModules.push(moduleName)}
+ >
+
+
+ {children}
+
+
+
+
+
+
+
+
)
diff --git a/packages/next/client/components/hooks-client-context.ts b/packages/next/shared/lib/hooks-client-context.ts
similarity index 86%
rename from packages/next/client/components/hooks-client-context.ts
rename to packages/next/shared/lib/hooks-client-context.ts
index b34157d876df..83d14c1451a0 100644
--- a/packages/next/client/components/hooks-client-context.ts
+++ b/packages/next/shared/lib/hooks-client-context.ts
@@ -2,8 +2,8 @@
import { createContext } from 'react'
-export const SearchParamsContext = createContext(null as any)
-export const PathnameContext = createContext(null as any)
+export const SearchParamsContext = createContext(null)
+export const PathnameContext = createContext(null)
export const ParamsContext = createContext(null as any)
export const LayoutSegmentsContext = createContext(null as any)
diff --git a/packages/next/shared/lib/router/adapters.ts b/packages/next/shared/lib/router/adapters.ts
index 5fae3ac15299..facd64c2a7ef 100644
--- a/packages/next/shared/lib/router/adapters.ts
+++ b/packages/next/shared/lib/router/adapters.ts
@@ -1,30 +1,81 @@
+import type { ParsedUrlQuery } from 'node:querystring'
import { AppRouterInstance } from '../app-router-context'
import { NextRouter } from './router'
/**
* adaptForAppRouterInstance implements the AppRouterInstance with a NextRouter.
+ *
+ * @param router the NextRouter to adapt
+ * @returns an AppRouterInstance
*/
export function adaptForAppRouterInstance(
- nextRouter: NextRouter
+ router: NextRouter
): AppRouterInstance {
return {
back(): void {
- nextRouter.back()
+ router.back()
},
forward(): void {
- nextRouter.forward()
+ router.forward()
},
refresh(): void {
- nextRouter.reload()
+ router.reload()
},
push(href: string): void {
- void nextRouter.push(href)
+ void router.push(href)
},
replace(href: string): void {
- void nextRouter.replace(href)
+ void router.replace(href)
},
prefetch(href: string): void {
- void nextRouter.prefetch(href)
+ void router.prefetch(href)
},
}
}
+
+/**
+ * transforms the ParsedUrlQuery into a URLSearchParams.
+ *
+ * @param query the query to transform
+ * @returns URLSearchParams
+ */
+function transformQuery(query: ParsedUrlQuery): URLSearchParams {
+ const params = new URLSearchParams()
+
+ for (const [name, value] of Object.entries(query)) {
+ if (Array.isArray(value)) {
+ for (const val of value) {
+ params.append(name, val)
+ }
+ } else if (typeof value !== 'undefined') {
+ params.append(name, value)
+ }
+ }
+
+ return params
+}
+
+/**
+ * adaptForSearchParams transforms the ParsedURLQuery into URLSearchParams.
+ *
+ * @param router the router that contains the query.
+ * @returns the search params in the URLSearchParams format
+ */
+export function adaptForSearchParams(router: NextRouter): URLSearchParams {
+ if (!router.isReady || !router.query) {
+ return new URLSearchParams()
+ }
+
+ return transformQuery(router.query)
+}
+
+/**
+ * adaptForPathname adapts the `asPath` parameter from the router to a pathname.
+ *
+ * @param asPath the asPath parameter to transform that comes from the router
+ * @returns pathname part of `asPath`
+ */
+export function adaptForPathname(asPath: string): string {
+ const url = new URL(asPath, 'http://f')
+ return url.pathname
+}