diff --git a/packages/e2e/next/cypress/e2e/shared/loader.cy.ts b/packages/e2e/next/cypress/e2e/shared/loader.cy.ts new file mode 100644 index 00000000..7962e445 --- /dev/null +++ b/packages/e2e/next/cypress/e2e/shared/loader.cy.ts @@ -0,0 +1,5 @@ +import { testLoader } from 'e2e-shared/specs/loader.cy' + +testLoader({ path: '/app/loader', nextJsRouter: 'app' }) + +testLoader({ path: '/pages/loader', nextJsRouter: 'pages' }) diff --git a/packages/e2e/next/src/app/app/loader/page.tsx b/packages/e2e/next/src/app/app/loader/page.tsx new file mode 100644 index 00000000..f0b78ab5 --- /dev/null +++ b/packages/e2e/next/src/app/app/loader/page.tsx @@ -0,0 +1,11 @@ +import { LoaderRenderer, loadSearchParams } from 'e2e-shared/specs/loader' +import type { SearchParams } from 'nuqs/server' + +type PageProps = { + searchParams: Promise +} + +export default async function Page({ searchParams }: PageProps) { + const serverValues = await loadSearchParams(searchParams) + return +} diff --git a/packages/e2e/next/src/pages/pages/loader.tsx b/packages/e2e/next/src/pages/pages/loader.tsx new file mode 100644 index 00000000..08d91e59 --- /dev/null +++ b/packages/e2e/next/src/pages/pages/loader.tsx @@ -0,0 +1,22 @@ +import { + type SearchParams, + LoaderRenderer, + loadSearchParams +} from 'e2e-shared/specs/loader' +import { GetServerSidePropsContext } from 'next' + +type PageProps = { + serverValues: SearchParams +} + +export default function Page({ serverValues }: PageProps) { + return +} + +export async function getServerSideProps({ query }: GetServerSidePropsContext) { + return { + props: { + serverValues: loadSearchParams(query) + } + } +} diff --git a/packages/e2e/react-router/v6/cypress/e2e/shared/loader.cy.ts b/packages/e2e/react-router/v6/cypress/e2e/shared/loader.cy.ts new file mode 100644 index 00000000..4b7b289c --- /dev/null +++ b/packages/e2e/react-router/v6/cypress/e2e/shared/loader.cy.ts @@ -0,0 +1,3 @@ +import { testLoader } from 'e2e-shared/specs/loader.cy' + +testLoader({ path: '/loader' }) diff --git a/packages/e2e/react-router/v6/src/react-router.tsx b/packages/e2e/react-router/v6/src/react-router.tsx index bae460f1..8e1540e5 100644 --- a/packages/e2e/react-router/v6/src/react-router.tsx +++ b/packages/e2e/react-router/v6/src/react-router.tsx @@ -37,6 +37,7 @@ const router = createBrowserRouter( + )) diff --git a/packages/e2e/react-router/v6/src/routes/loader.tsx b/packages/e2e/react-router/v6/src/routes/loader.tsx new file mode 100644 index 00000000..235446f1 --- /dev/null +++ b/packages/e2e/react-router/v6/src/routes/loader.tsx @@ -0,0 +1,11 @@ +import { LoaderRenderer, loadSearchParams } from 'e2e-shared/specs/loader' +import { useLoaderData, type LoaderFunctionArgs } from 'react-router-dom' + +export function loader({ request }: LoaderFunctionArgs) { + return loadSearchParams(request) +} + +export default function Page() { + const serverValues = useLoaderData() as Awaited> + return +} diff --git a/packages/e2e/react-router/v7/app/routes.ts b/packages/e2e/react-router/v7/app/routes.ts index df91927a..67987f62 100644 --- a/packages/e2e/react-router/v7/app/routes.ts +++ b/packages/e2e/react-router/v7/app/routes.ts @@ -18,5 +18,6 @@ export default [ route('/routing/useQueryStates/other', './routes/routing.useQueryStates.other.tsx'), route('/shallow/useQueryState', './routes/shallow.useQueryState.tsx'), route('/shallow/useQueryStates', './routes/shallow.useQueryStates.tsx'), + route('/loader', './routes/loader.tsx') ]) ] satisfies RouteConfig diff --git a/packages/e2e/react-router/v7/app/routes/loader.tsx b/packages/e2e/react-router/v7/app/routes/loader.tsx new file mode 100644 index 00000000..95505a8a --- /dev/null +++ b/packages/e2e/react-router/v7/app/routes/loader.tsx @@ -0,0 +1,13 @@ +import { LoaderRenderer, loadSearchParams } from 'e2e-shared/specs/loader' +import type { LoaderFunctionArgs } from 'react-router' +import type { Route } from './+types/loader' + +export function loader({ request }: LoaderFunctionArgs) { + return loadSearchParams(request) +} + +export default function Page({ + loaderData: serverValues +}: Route.ComponentProps) { + return +} diff --git a/packages/e2e/react-router/v7/cypress/e2e/shared/loader.cy.ts b/packages/e2e/react-router/v7/cypress/e2e/shared/loader.cy.ts new file mode 100644 index 00000000..4b7b289c --- /dev/null +++ b/packages/e2e/react-router/v7/cypress/e2e/shared/loader.cy.ts @@ -0,0 +1,3 @@ +import { testLoader } from 'e2e-shared/specs/loader.cy' + +testLoader({ path: '/loader' }) diff --git a/packages/e2e/remix/app/routes/loader.tsx b/packages/e2e/remix/app/routes/loader.tsx new file mode 100644 index 00000000..a9e84620 --- /dev/null +++ b/packages/e2e/remix/app/routes/loader.tsx @@ -0,0 +1,12 @@ +import type { LoaderFunctionArgs } from '@remix-run/node' +import { useLoaderData } from '@remix-run/react' +import { LoaderRenderer, loadSearchParams } from 'e2e-shared/specs/loader' + +export function loader({ request }: LoaderFunctionArgs) { + return loadSearchParams(request) +} + +export default function Page() { + const serverValues = useLoaderData() + return +} diff --git a/packages/e2e/remix/cypress/e2e/shared/loader.cy.ts b/packages/e2e/remix/cypress/e2e/shared/loader.cy.ts new file mode 100644 index 00000000..4b7b289c --- /dev/null +++ b/packages/e2e/remix/cypress/e2e/shared/loader.cy.ts @@ -0,0 +1,3 @@ +import { testLoader } from 'e2e-shared/specs/loader.cy' + +testLoader({ path: '/loader' }) diff --git a/packages/e2e/shared/specs/loader.cy.ts b/packages/e2e/shared/specs/loader.cy.ts new file mode 100644 index 00000000..cd9b3fef --- /dev/null +++ b/packages/e2e/shared/specs/loader.cy.ts @@ -0,0 +1,10 @@ +import { createTest } from '../create-test' + +export const testLoader = createTest('Loader', ({ path }) => { + it('loads state from the URL', () => { + cy.visit(path + '?test=pass&int=42') + cy.contains('#hydration-marker', 'hydrated').should('be.hidden') + cy.get('#test').should('have.text', 'pass') + cy.get('#int').should('have.text', '42') + }) +}) diff --git a/packages/e2e/shared/specs/loader.tsx b/packages/e2e/shared/specs/loader.tsx new file mode 100644 index 00000000..c0e6470e --- /dev/null +++ b/packages/e2e/shared/specs/loader.tsx @@ -0,0 +1,27 @@ +import { + createLoader, + type inferParserType, + parseAsInteger, + parseAsString +} from 'nuqs/server' + +const searchParams = { + test: parseAsString, + int: parseAsInteger +} + +export type SearchParams = inferParserType +export const loadSearchParams = createLoader(searchParams) + +type LoaderRendererProps = { + serverValues: inferParserType +} + +export function LoaderRenderer({ serverValues }: LoaderRendererProps) { + return ( + <> +
{serverValues.test}
+
{serverValues.int}
+ + ) +}