Reputation: 6788
How can I remove or update query params without refreshing the page in Next JS (React)?
/about?login=success&something=yes
?login=success&something=yes
from the URL without refreshing the page. The URL after clicking the button will be /about
How can I achieve it?
As mentioned in this thread, I know that is possible to remove query params or query strings with Router. But, useLocation
and useHistory
are not avaliable on next/router
.
Upvotes: 49
Views: 126528
Reputation: 61
'use client'
import { useSearchParams, usePathname, useRouter } from 'next/navigation'
import { Chip } from '@/components/ui/chip'
export default function FilterReset() {
const searchParams = useSearchParams()
const pathname = usePathname()
const { replace } = useRouter()
const customerFilterId = searchParams.get('customer')
const handleResetFilters = () => {
const params = new URLSearchParams(searchParams)
params.delete('customer')
replace(`${pathname}?${params.toString()}`)
}
if (!customerFilterId) {
return null
}
return (
<Chip
onClose={handleResetFilters}
variant="bordered"
color="danger"
>
Reset
</Chip>
)
}
Upvotes: 0
Reputation: 1835
For Next.js 13 & above, you usually want to keep pathname and all other query params the same while deleting one specific query param (e.g. foo
) you can do so like this:
'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'
const router = useRouter()
const pathname = usePathname()
const searchParams = useSearchParams()
const nextSearchParams = new URLSearchParams(searchParams.toString())
nextSearchParams.delete('foo')
router.replace(`${pathname}?${nextSearchParams}`)
(Upgraded answer of @sebastian-voráč-msc)
Upvotes: 18
Reputation: 712
Another approach is removing the query parameter server-side using a middleware function. With the app router you can create a middleware.js
file inside your app
directory with the following content:
import { NextResponse } from 'next/server';
export function middleware(req) {
const url = req.nextUrl.clone();
const value = url.searchParams.get('your_query_parameter')
if (value) {
url.searchParams.delete('your_query_parameter')
return NextResponse.redirect(url);
}
return NextResponse.next();
}
Upvotes: 1
Reputation: 2004
My case is canonical url, so should be available on build, the approach:
const router = useRouter();
const url = new URL(PUBLIC_URL + router.asPath);
const canonicalUrl = PUBLIC_URL + url.pathname;
note: this using pages
Upvotes: 0
Reputation: 3186
For Next 13+, if you're working with the app
router, you'll have to use a combination of useSearchParams
, usePathname
, URLSearchParams
, and useRouter
from next/navigation
to achieve this.
import { usePathname, useRouter, useSearchParams } from "next/navigation";
const router = useRouter();
const pathname = usePathname();
const query = useSearchParams();
const params = new URLSearchParams(query);
//do your modifications on search params
params.delete("search");
const newUrl = `${pathname}?${params.toString()}`;
router.replace(newUrl);
Upvotes: 1
Reputation: 1
Since router.query
is a simple object, you can delete query params by mutating router.query
.
Lets say you have query params ?size=M&color=red
:
// INIT
const router = useRouter();
router.push({
pathname: router.pathname,
query: { ...router.query, color: "red", size: "M" }
},
undefined,
{}
);
And you need to remove only ONE param, for example size=M
.
All you need to do is directly delete the field from router.query
object and push your mutation (spread operator to keep all other params):
// DELETE ONE
delete router.query.color;
router.push({
pathname: router.pathname,
query: { ...router.query }
},
undefined,
{}
);
If you want to remove ALL params, just simply push null
to query
field:
// DELETE ALL
router.push({
pathname: router.pathname,
query: null
},
undefined,
{}
);
Upvotes: 0
Reputation: 1094
We can use useRouter
hook from next/router
to access the current route and query parameters. To remove or update parameters without refreshing the page, we can use the push
method of the router object.
Here is an example of how we can remove query parameters from the URL:
const router = useRouter();
function removeQueryHandler() {
const { pathname } = router;
router.push({ pathname });
}
CodeSandbox: link
Another Approach:
We can use shallow routing as well to remove or update query parameters without triggering a full page refresh in Next.js. Like this:
function removeQueryHandler() {
const { pathname } = router;
router.push({ pathname }, undefined, { shallow: true });
}
Upvotes: 2
Reputation: 21
Maybe this solution will be a bit more neat:
const { query, replace } = useRouter();
const setActiveTab = useCallback((tabName: string) => {
const { group, ...paramsExceptGroup } = query || {};
replace(
{
query: tabName === defaultTabName ? paramsExceptGroup : { ...paramsExceptGroup, group: tabName },
},
undefined,
{ shallow: true },
).then();
}, [query, defaultTabName]);
So if "tab" is default, I drop it with spread operator and remove it from query.
Upvotes: 1
Reputation: 3217
This should work for you well:
router.replace('/about', undefined, { shallow: true });
The shallow routing will not cause page refresh and data refetch. Learn more here.
Even though the above solution removes the query params without causing a refresh, they do cause re-render.
Unfortunately, Nextjs has no built in solution to remove query param without causing a re-render. But, there's a native solution:
window.history.replaceState({ ...window.history.state, as: '/about', url: '/about' }, '', '/about');
Upvotes: 2
Reputation: 50338
You can use next/router
to remove the query params in the URL.
const router = useRouter();
router.replace('/about', undefined, { shallow: true });
Use replace
to prevent adding a new URL entry into the history (otherwise just use push
), and shallow: true
allows you to change the URL without running data fetching methods. This will cause a re-render but will not refresh the page per se.
The above solution will remove all query parameters from the URL. If you want to only remove a specific parameter you can use the code below instead.
const removeQueryParam = (param) => {
const { pathname, query } = router;
const params = new URLSearchParams(query);
params.delete(param);
router.replace(
{ pathname, query: params.toString() },
undefined,
{ shallow: true }
);
};
removeQueryParam('something');
Upvotes: 81
Reputation: 73
For next/router, along with typescript, none of the above answers seem to be working anymore.
The following snippet takes all query parameters and removes one by the key while keeping all others untouched.
const { push, query } = useRouter();
const removeQueryParam = (param) => {
const updatedQuery = query;
delete updatedQuery[param];
push({ query: updatedQuery }, undefined, { shallow: true });
}
Usage (in clickHandler or wherever):
removeQueryParam('queryParamName');
Note: Use router.replace
instead of router.push
if you don't want to add the new URL to the browser history back stack.
Upvotes: 3
Reputation: 1
Good way to do it when you know the query param you want to remove based on https://github.com/jbranchaud/til/blob/master/nextjs/remove-a-query-param-from-the-url.md
const router = useRouter();
useEffect(() => {
// extract the value from the query params
const { someKey, ...updatedQuery } = router.query;
// create an updated router path object
const newPathObject = {
pathname: router.pathname,
query: updatedQuery,
};
// update the URL, without re-triggering data fetching
void router.push(newPathObject, undefined, { shallow: true });
}, [router]);
Upvotes: 0
Reputation: 3538
If you want remove single or multiple params from query,
const router = useRouter();
/**
* If removeList is empty, the function removes all params from url.
* @param {*} router
* @param {*} removeList
*/
const removeQueryParamsFromRouter = (router, removeList = []) => {
if (removeList.length > 0) {
removeList.forEach((param) => delete router.query[param]);
} else {
// Remove all
Object.keys(router.query).forEach((param) => delete router.query[param]);
}
router.replace(
{
pathname: router.pathname,
query: router.query
},
undefined,
/**
* Do not refresh the page
*/
{ shallow: true }
);
};
const anyFunction = () => {
// "/about?firstParam=5&secondParam=10"
removeQueryParamsFromRouter(router, ['myParam']);
// "/about?secondParam=10"
};
Upvotes: 5
Reputation: 4693
You usually want to keep pathname and all other query params
the same while deleting one specific query param (in example shouldRefetchUser
) you can do so like this:
const router = useRouter()
const { pathname, query } = router
delete router.query.shouldRefetchUser
router.replace({ pathname, query }, undefined, { shallow: true })
(Upgraded answer of @juliomalves)
Upvotes: 9
Reputation: 59
You can simply use "router.push" or "router.replace" with "shallow: true", this will remove the query param without reloading the page.
const router = useRouter();
router.replace('/about', undefined, { shallow: true });
Or if you want to delete single query then this quick and easy method will help you
eg. /about?login=success&something=yes
const router = useRouter();
// perform this inside function call or button click etc
delete router.query.something;
router.push(router)
now the updated route will be
/about?login=success
Upvotes: 4
Reputation: 99
import {NextRouter} from 'next/router'
export const removeQueryParams = (
router: NextRouter,
paramsToRemove: Array<string> = []
) => {
if (paramsToRemove.length > 0) {
paramsToRemove.forEach((param) => delete router.query[param])
} else {
// Remove all query parameters
Object.keys(router.query).forEach((param) => delete router.query[param])
}
router.replace(
{
pathname: router.pathname,
query: router.query,
},
undefined,
/**
* Do not refresh the page when the query params are removed
*/
{shallow: true}
)
}
const anyFunction = () => {
// "/about?firstParam=5&secondParam=10"
removeQueryParamsFromRouter(router, ['myParam']);
// "/about?secondParam=10"
};
The original answer mentioned here throws an error as the object is undefined, also it is the typescript version of it.
Upvotes: 0
Reputation: 4559
You can remove query param from router object by []:
const router = useRouter();
router.query.something = [];
Upvotes: 0
Reputation: 167
my solution to similiar problem of mine is this:
push(`${asPath.split('?')[0]}?comp=${id}`);
or if you want to have reusable function:
function delQuery(asPath) {
return asPath.split('?')[0]
}
...
const {push, asPath} = useRouter()
push(`${delQuery(asPath)}?comp=${id}`);
Upvotes: 7
Reputation: 680
According to the History, you can using history.replaceState
to implement this.
window.history.replaceState(null, '', '/about')
Upvotes: 13
Reputation: 864
Nextjs has useRouter
hook which can be used to changed url programmatically.
Link to the docs.
Upvotes: -2