Reputation: 696
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
?
Upvotes: 6
Views: 7860
Reputation: 50288
You can modify your addFilter
function to add the desired skill
value to the skill
query parameter as an array. Making sure to deduplicate the array items, to avoid having repeated filters in the URL.
const convertQueryParamToArray = (queryParam: string) => !queryParam ? [] : [queryParam];
const addFilter = async (skill: string) => {
// Force `skill` query param into an array
const currentSkillArray = Array.isArray(router.query.skill)
? router.query.skill
: convertQueryParamToArray(router.query.skill);
// Deduplicate skills with same value
const newSkillArray = [...new Set([...currentSkill, skill.toLowerCase()])];
router.push({
query: { ...router.query, skill: newSkillArray }
});
};
Given the above function and assuming your URL starts as /?page=1
, calling addFilter('html')
would make the URL become /?page=1&skill=html
. A following call to addFilter('css')
would update the URL to /?page=1&skill=html&skill=css
. And so on.
Upvotes: 0
Reputation: 146
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
Upvotes: 5
Reputation: 1066
Instead of sending a single value you can add the skills to an array first. And then use join() to separate the values by a separator. Ex:
query: { skills: skills.join(",") }
And of course you need to explode it again on the other side..
Upvotes: 3