Skip to content

Commit

Permalink
feat: port useSearchParams and usePathname to pages
Browse files Browse the repository at this point in the history
  • Loading branch information
wyattjoh committed Oct 27, 2022
1 parent 1916663 commit 88806a0
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 50 deletions.
2 changes: 1 addition & 1 deletion packages/next/client/components/app-router.tsx
Expand Up @@ -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'

Expand Down
2 changes: 1 addition & 1 deletion packages/next/client/components/navigation.ts
Expand Up @@ -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(
Expand Down
36 changes: 24 additions & 12 deletions packages/next/client/index.tsx
Expand Up @@ -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')
Expand Down Expand Up @@ -309,17 +317,21 @@ function AppContainer({
}
>
<AppRouterContext.Provider value={adaptForAppRouterInstance(router)}>
<RouterContext.Provider value={makePublicRouterInstance(router)}>
<HeadManagerContext.Provider value={headManager}>
<ImageConfigContext.Provider
value={
process.env.__NEXT_IMAGE_OPTS as any as ImageConfigComplete
}
>
{children}
</ImageConfigContext.Provider>
</HeadManagerContext.Provider>
</RouterContext.Provider>
<SearchParamsContext.Provider value={adaptForSearchParams(router)}>
<PathnameContext.Provider value={adaptForPathname(asPath)}>
<RouterContext.Provider value={makePublicRouterInstance(router)}>
<HeadManagerContext.Provider value={headManager}>
<ImageConfigContext.Provider
value={
process.env.__NEXT_IMAGE_OPTS as any as ImageConfigComplete
}
>
{children}
</ImageConfigContext.Provider>
</HeadManagerContext.Provider>
</RouterContext.Provider>
</PathnameContext.Provider>
</SearchParamsContext.Provider>
</AppRouterContext.Provider>
</Container>
)
Expand Down
66 changes: 39 additions & 27 deletions packages/next/server/render.tsx
Expand Up @@ -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
Expand Down Expand Up @@ -645,32 +653,36 @@ export async function renderToHTML(

const AppContainer = ({ children }: { children: JSX.Element }) => (
<AppRouterContext.Provider value={appRouter}>
<RouterContext.Provider value={router}>
<AmpStateContext.Provider value={ampState}>
<HeadManagerContext.Provider
value={{
updateHead: (state) => {
head = state
},
updateScripts: (scripts) => {
scriptLoader = scripts
},
scripts: initialScripts,
mountedInstances: new Set(),
}}
>
<LoadableContext.Provider
value={(moduleName) => reactLoadableModules.push(moduleName)}
>
<StyleRegistry registry={jsxStyleRegistry}>
<ImageConfigContext.Provider value={images}>
{children}
</ImageConfigContext.Provider>
</StyleRegistry>
</LoadableContext.Provider>
</HeadManagerContext.Provider>
</AmpStateContext.Provider>
</RouterContext.Provider>
<SearchParamsContext.Provider value={adaptForSearchParams(router)}>
<PathnameContext.Provider value={adaptForPathname(asPath)}>
<RouterContext.Provider value={router}>
<AmpStateContext.Provider value={ampState}>
<HeadManagerContext.Provider
value={{
updateHead: (state) => {
head = state
},
updateScripts: (scripts) => {
scriptLoader = scripts
},
scripts: initialScripts,
mountedInstances: new Set(),
}}
>
<LoadableContext.Provider
value={(moduleName) => reactLoadableModules.push(moduleName)}
>
<StyleRegistry registry={jsxStyleRegistry}>
<ImageConfigContext.Provider value={images}>
{children}
</ImageConfigContext.Provider>
</StyleRegistry>
</LoadableContext.Provider>
</HeadManagerContext.Provider>
</AmpStateContext.Provider>
</RouterContext.Provider>
</PathnameContext.Provider>
</SearchParamsContext.Provider>
</AppRouterContext.Provider>
)

Expand Down
Expand Up @@ -2,8 +2,8 @@

import { createContext } from 'react'

export const SearchParamsContext = createContext<URLSearchParams>(null as any)
export const PathnameContext = createContext<string>(null as any)
export const SearchParamsContext = createContext<URLSearchParams | null>(null)
export const PathnameContext = createContext<string | null>(null)
export const ParamsContext = createContext(null as any)
export const LayoutSegmentsContext = createContext(null as any)

Expand Down
65 changes: 58 additions & 7 deletions 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
}

0 comments on commit 88806a0

Please sign in to comment.