Raju Ahammad
Raju Ahammad

Reputation: 1212

How to get URL query string on Next.js static site generation?

I want to get query string from URL on Next.js static site generation.

I found a solution on SSR but I need one for SSG.

Thanks

enter image description here

Upvotes: 12

Views: 30037

Answers (5)

Dom
Dom

Reputation: 117

you don't have access to the query string (?a=b) for SSG (which is static content - always the same - executed only on build time).

But if you have to use query string variables then you can:

  1. still statically pre-render content on build time (SSG) or on the fly (ISR) and handle this route by rewrite (next.config.js or middleware)
  2. use SSR
  3. use CSR (can also use SWR)

Upvotes: 0

teleaziz
teleaziz

Reputation: 2240

As other answers mentioned, since SSG doesn't happen at request time, you wouldn't have access to the query string or cookies in the context, but there's a solution I wrote a short article about it here https://dev.to/teleaziz/using-query-params-and-cookies-in-nextjs-static-pages-kbb

TLDR;

Use a middleware that encodes the query string as part of the path,

// middleware.js file
import { NextResponse } from 'next/server'
import { encodeOptions } from '../utils';

export default function middleware(request) {
  if (request.nextUrl.pathname === '/my-page') {
    const searchParams = request.nextUrl.searchParams
    const path = encodeOptions({
      // you can pass values from cookies, headers, geo location, and query string
      returnVisitor: Boolean(request.cookies.get('visitor')),
      country: request.geo?.country,
      page: searchParams.get('page'),
    })

    return NextResponse.rewrite(new URL(`/my-page/${path}`, request.nextUrl))
  }
  return NextResponse.next()
}

Then make your static page a folder that accepts a [path]

// /pages/my-page/[path].jsx file
import { decodeOptions } from '../../utils'

export async function getStaticProps({
  params,
}) {
  const options = decodeOptions(params.path)
  return {
    props: {
      options,
    }
  }
}

export function getStaticPaths() {
  return {
    paths: [],
    fallback: true
  }
}

export default function MyPath({ options }) {
  return <MyPage
    isReturnVisitor={options.returnVisitor}
    country={options.country} />
}

And your encoding/decoding functions can be a simple JSON.strinfigy

// utils.js
// https://github.com/epoberezkin/fast-json-stable-stringify
import stringify from 'fast-json-stable-stringify'

export function encodeOptions(options) {
  const json = stringify(options)
  return encodeURI(json);
}

export function decodeOptions(path) {
  return JSON.parse(decodeURI(path));
}

Upvotes: 2

juliomalves
juliomalves

Reputation: 50308

You don't have access to query params in getStaticProps since that's only run at build-time on the server.

However, you can use router.query in your page component to retrieve query params passed in the URL on the client-side.

// pages/shop.js

import { useRouter } from 'next/router'

const ShopPage = () => {
    const router = useRouter()
    console.log(router.query) // returns query params object

    return (
        <div>Shop Page</div>
    )
}

export default ShopPage

If a page does not have data fetching methods, router.query will be an empty object on the page's first load, when the page gets pre-generated on the server.

From the next/router documentation:

query: Object - The query string parsed to an object. It will be an empty object during prerendering if the page doesn't have data fetching requirements. Defaults to {}

As @zg10 mentioned in his answer, you can solve this by using the router.isReady property in a useEffect's dependencies array.

From the next/router object documentation:

isReady: boolean - Whether the router fields are updated client-side and ready for use. Should only be used inside of useEffect methods and not for conditionally rendering on the server.

Upvotes: 0

Umut &#199;iftci
Umut &#199;iftci

Reputation: 179

import { useRouter } from "next/router";
import { useEffect } from "react";

const router = useRouter();

useEffect(() => {
    if(!router.isReady) return;
    const query = router.query;
  }, [router.isReady, router.query]);

It works.

Upvotes: 15

mendespedro
mendespedro

Reputation: 516

I actually found a way of doing this

const router = useRouter()

useEffect(() => {
    const params = router.query
    console.log(params)
}, [router.query])

Upvotes: 1

Related Questions