Search code examples
reactjsnext.jsquery-stringnext-router

Add multiple query params with the same key with next/router


I'm filtering results from an API utilizing query parameters in my Next.js app. I want to use useRouter() to push multiple different filters with the same key, so my query params could look like:

?page=1&skill=html&skill=css&skill=js

And I can pass each of those parameters to my API request. Right now, when I'm trying to add a skill parameter I'm using router.push to do it, like this:

const router = useRouter();

const addFilter = (skill: string) => router.push({ query: { ...router.query, skill: skill.toLowerCase() } });

But obviously it's overwriting the previous skill, so I'm only ever getting one of them in the URL. How can I go about adding additional query parameters with the same key, preferably using useRouter() or next/router?


Solution

  • To manipulate the query params in the URL in Next.js I use a custom hook that uses what useRouter offers, but I also add some util methods, in this case, to add a filter to the URL I have the method addParam.

    This is the body of the custom hook.

    const useRouterFilter = () =>{
      const { pathname, query, push } = useRouter()
    
      return {
        addParam,
        ...
      }
    }
    

    And this would be the addFilter method inside the hook:

      /**
       * Adds a query param to the URL string. Multiple params with the same name
       * and different values can be added.
       * @param name The name of the param.
       * @param value The value of the param.
       */
      const addParam = (name: string, value: string | boolean | number) => {
        const { [name]: param, ...rest } = query
        let newQuery
    
        if (!param) {
          newQuery = { ...rest, [name]: encodeURIComponent(value) }
        } else if (Array.isArray(param)) {
          if (param.indexOf(encodeURIComponent(value)) > -1) return
          newQuery = { ...rest, [name]: [...param, encodeURIComponent(value)] }
        } else {
          if (param === encodeURIComponent(value)) return
          newQuery = { ...rest, [name]: [param, encodeURIComponent(value)] }
        }
    
        push(
          {
            pathname,
            query: newQuery,
          },
          undefined,
          { shallow: true }
        )
      }
    

    In this case I use push to add the parameters to the URL, but replace could also be used.

    The full hook can be copied from the following Gist