Hey Guys I am stuck could you please help. I want to update query param on input change handler.
Points to be Noted
Text Input Child Component:
const TextInputComp = () => {
function onInputChange () {
/* Logic to update only value query param not any other one if exist more query param */
}
return (
<input type="text" onChange={onInputChange} />
)
Parent Comp:
function ParentComp () {
const [valueQueryParam,setValueQueryParam] = useState() /* only value Query param should capture in useState */
useEffect(()=>{
/* Your Logic to get value query Param fom URL with every time it changes */
},[/* Your Dependency */])
return(
<div>
<TextInputComp />
{valueQueryParam} your realtime query param text
</div>
)
}
Please do not duplicate this question
This is exactly what nuqs was built to do (disclaimer: I'm the author).
There are a couple of things to watch out for when connecting a high-frequency update source (text input, <input type="range"> slider) to the URL.
One is that browsers rate-limit calls to the History API. Around 20 calls per second for Chrome and Firefox, but Safari has much lower limits (1000 calls per 30s). So you'll want to throttle your updates.
The issue of throttling is that a controlled input will become out of sync with its state, and will result to a janky experience.
nuqs uses an internal state that updates as React.useState would, but defers and throttles updates to the URL in parallel, to reach eventual consistency.
Your example would then look like this:
'use client'
import { useQueryState, parseAsString } from 'nuqs'
const TextInputComp = () => {
const [search, setSearch] = useQueryState(
'search',
parseAsString.withDefault('')
)
return (
<input
type="text"
value={search}
onChange={e => setSearch(e.target.value || null)
// null clears the query key if the input is empty
/>
)
Then your parent component (or anything else in the tree) can use the same hook to read the value:
function ParentComp () {
const [search, setSearch] = useQueryState(
'search',
parseAsString.withDefault('')
)
return (
<div>
<TextInputComp />
{search} your realtime query param text
</div>
)
}
As a matter of fact, this exact use-case is showcased on the landing page demo: https://nuqs.47ng.com/?hello=AL+Faiz+Ahmed
First of all, There are three main types of routing/navigation:
Hard Navigation would not be the worst choice to update the search param with since it reloads the entire page, skip the browser cache, destroy client-side state, etc...
Still two types:
Good to know: Refreshing the page
onChangeis not a good UX. You can useonBlurinstead
to push search param softly:
import { useRouter, usePathname, useSearchParams } from "next/navigation";
// ...
const pathname = usePathname(); // let's get the pathname to make the component reusable - could be used anywhere in the project
const router = useRouter();
const currentSearchParams = useSearchParams();
function onInputBlur(event) {
// let's assume we want to push the `query` searchParam
const query = event.target.value;
const updatedSearchParams = new URLSearchParams(currentSearchParams.toString())
updatedSearchParams.set("query", query)
router.push(pathname + "?" + updatedSearchParams.toString())
}
const currentSearchParams = useSearchParams();
function onInputBlur(event) {
const query = event.target.value;
const updatedSearchParams = new URLSearchParams(currentSearchParams.toString())
updatedSearchParams.set("query", query)
window.history.pushState(null, "", "?" + updatedSearchParams.toString())
}
Keep away from the last option if you are using (a bit) old version of Next.js because it was introduced lately at 14.0.x and been enabled by default since 14.1.0. So, if anyone reads this answer and uses older next.js version this might not work as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With