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

5

12

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

Disprize answered 10/2, 2021 at 9:6 Comment(3)
You can try using router.asPath and parse the query yourself with a library like query-string:Modernity
github.com/zeit/next.js/issues/4804#issuecomment-460754433Modernity
Relevant feature request: github.com/vercel/next.js/discussions/17269Steelworks
G
15

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.

Gratuity answered 2/8, 2021 at 6:21 Comment(2)
Is it necessary to include router.query in the useEffect dependencies? It seems like router.isReady is enoughNecropolis
@Necropolis Only if you're using router.query inside the useEffect. Otherwise, you don't need to.Henriettahenriette
O
2

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));
}
Orchardist answered 15/10, 2022 at 21:17 Comment(0)
B
1

I actually found a way of doing this

const router = useRouter()

useEffect(() => {
    const params = router.query
    console.log(params)
}, [router.query])
Belay answered 7/6, 2021 at 19:9 Comment(2)
I don't think this will work, useEffect is for client side only stuff (e.g. that requires window), and OP wants to prerender on server.Steelworks
I know, but it's impossible to do what he wants without getting the query on client, as next js documentation says: "getStaticProps generates the page at build time. There's no possible way to know the custom query params your visitors can use at build time." The only way us using getServerSideProps. But then you'll lose the static optimization.Belay
H
0

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.

Henriettahenriette answered 10/2, 2021 at 13:50 Comment(2)
Actually on the first load don't have any query string. After the action query string generates in the URL. So the first load will return a null value and give an error.Disprize
Can't you check the query string after that "action" happens? Same logic applies. If you could add your code to the question, that will also be helpful.Henriettahenriette
P
0

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)
Plainsman answered 14/11, 2022 at 14:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.