Deleting Search Param is not re-rendering react server component page
Unanswered
West African Lion posted this in #help-forum
West African LionOP
I am following a pattern that is described in the [NextJS Help](https://nextjs.org/learn/dashboard-app/adding-search-and-pagination) to implement search and filtering against a table of records.
I am finding that in certain cases the page will not re-render when the search parameter is deleted (meaning the filter will still apply even though the filter param is no longer present!). Specifically this occurs in the following case:
1. The user hits the page with the query param present: e.g. https://website.com/catalog?query="hello"
2. If the query is removed (e.g. the user toggles off a filter button) then next js does not re-render for the user.
Interestingly it works fine if the user hits https://website.com/catalog, and then creates the query, and then removes it via another user interaction. I.e. the filter correctly is added and removed...
Here is the specific section of code that manipulates the parameters:
I am finding that in certain cases the page will not re-render when the search parameter is deleted (meaning the filter will still apply even though the filter param is no longer present!). Specifically this occurs in the following case:
1. The user hits the page with the query param present: e.g. https://website.com/catalog?query="hello"
2. If the query is removed (e.g. the user toggles off a filter button) then next js does not re-render for the user.
Interestingly it works fine if the user hits https://website.com/catalog, and then creates the query, and then removes it via another user interaction. I.e. the filter correctly is added and removed...
Here is the specific section of code that manipulates the parameters:
'use client';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import RegionFilterButtonGroup from '@/components/RegionFilterButtonGroup';
import { getRegionCodes } from './utils';
export default function FilterByRegion() {
const pathname = usePathname();
const { replace } = useRouter();
const searchParams = useSearchParams();
const handleChange = (value: string[]) => {
const params = new URLSearchParams(searchParams);
if (value.length > 0) {
params.set('region', value.join(','));
} else {
params.delete('region');
}
replace(`${pathname}?${params.toString()}`, { scroll: false });
};
return (
<RegionFilterButtonGroup
availableRegions={['Antarctic', 'Arctic']}
initialValue={getRegionCodes(searchParams.get('region') ?? '')}
singleSelect={false}
onSelectionChange={handleChange}
/>
);
}6 Replies
American Crow
First: Don't know if this is related but you are not passing a value in your
Second: How is the query removed? Do you just manually delete it from the URL?
If yes I'd start with a console.log in the server component and client component to see what is rerendered
onSelectionChange to handleChangeonSelectoinChange={(e)=>handleChange(e.target.value)}Second: How is the query removed? Do you just manually delete it from the URL?
If yes I'd start with a console.log in the server component and client component to see what is rerendered
West African LionOP
1) The function is passed to the child component where it is called with the required arguments (in this case an array of strings)
2) The query is removed using the next/navigation replace function. when the array of selected regions is empty, then the param is deleted from the url string and the current navigation url is replaced with the new value. I have checked whether the Page re-renders or not, and can see that is does not when the user goes through the workflow described above (i.e. navigating directly to the page with the query and then removing it)
American Crow
Hm i am trying to reproduce with a minimal example:
So now when i go to http://localhost:3000/3?region=eu
than click the "all" button
it still rerenders the Selected Region <h2> for me to an empty string
"use client"
import Link from "next/link"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
export default function Page() {
const pathname = usePathname()
const {replace} = useRouter()
const searchParams = useSearchParams()
const selectedRegeion = searchParams.get("region") ?? ""
return (
<div>
<h1>Pathname: {pathname}</h1>
<h2>Selected Region: {selectedRegeion}</h2>
<Link href="?region=us">US</Link>
<Link href="?region=eu">EU</Link>
{/* Delete Regions */}
<Link href="?">All</Link>
</div>
)
}So now when i go to http://localhost:3000/3?region=eu
than click the "all" button
it still rerenders the Selected Region <h2> for me to an empty string
American Crow
With a remove function similar to yours:
Still works when i hit http://localhost:3000/3?region=eu click on
"use client"
import Link from "next/link"
import { usePathname, useRouter, useSearchParams } from "next/navigation"
export default function Page() {
const pathname = usePathname()
const {replace} = useRouter()
const searchParams = useSearchParams()
const selectedRegeion = searchParams.get("region") ?? ""
function removeRegionParam() {
const params = new URLSearchParams(searchParams)
params.delete("region")
replace(`${pathname}?${params.toString()}`)
}
return (
<div>
<h1>Pathname: {pathname}</h1>
<h2>Selected Region: {selectedRegeion}</h2>
<Link href="?region=us">US</Link>
<Link href="?region=eu">EU</Link>
{/* Delete Regions */}
<Link href="?">All</Link>
{/* With a Remove Button */}
<button onClick={removeRegionParam}>Remove</button>
</div>
)
}Still works when i hit http://localhost:3000/3?region=eu click on
Remove my component rerenders and shows an empty Selected RegionWest African LionOP
@American Crow Thanks for the help. I found that the client component was picking up the change in the url search params, but not the server component for some reason? My work around has now been to add some logic inside the filters... Its a bit hacky, but now working better:
'use client';
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import React from 'react';
import RegionFilterButtonGroup from '@/components/RegionFilterButtonGroup';
import { getRegionCodes } from './utils';
export default function FilterByRegion() {
const pathname = usePathname();
const { replace } = useRouter();
const searchParams = useSearchParams();
const [value, setValue] = React.useState<string[]>(
getRegionCodes(searchParams.get('region') ?? ''),
);
React.useEffect(() => {
const params = new URLSearchParams(searchParams);
const region = params.get('region');
console.log(region);
if (region === null) {
setValue([]);
}
if (params.get('region') === '') {
params.delete('region');
replace(`${pathname}?${params.toString()}`, { scroll: false });
}
}, [searchParams, pathname, replace]);
const handleChange = (value: string[]) => {
const params = new URLSearchParams(searchParams);
setValue(value);
params.set('region', value.join(','));
replace(`${pathname}?${params.toString()}`, { scroll: false });
};
return (
<RegionFilterButtonGroup
availableRegions={['Antarctic', 'Arctic']}
value={value}
singleSelect={false}
onSelectionChange={handleChange}
/>
);
}