Next.js Discord

Discord Forum

How to add loader to Search debouncer

Answered
Yellowstripe scad posted this in #help-forum
Open in Discord
Yellowstripe scadOP
export default function Search() {
    const searchParams = useSearchParams();
    const { replace } = useRouter();
    const pathname = usePathname();
    const handleSearch = useDebouncedCallback((term) => {
        const params = new URLSearchParams(searchParams);
        params.set('page', '1');
        if (term) {
            params.set('query', term);
        } else {
            params.delete('query');
        }
        replace(`${pathname}?${params.toString()}`);
    }, 300);
    return (
        <>
            <Input
                type="text" 
                placeholder="Search" 
                className="w-full h-12" 
                onChange={(e) => {
                    handleSearch(e.target.value);
                }}
                defaultValue={searchParams.get('query')?.toString()}
            />
        </>
    )
}


I want to add a loader, which is the component <Loader /> I have imported. I'm not sure how to make that work.
Answered by Ray
export default function Search() {
    const searchParams = useSearchParams();
    const { replace } = useRouter();
    const pathname = usePathname();
    const [isPending, startTransition] = useTransition()
    const handleSearch = useDebouncedCallback((term) => {
        const params = new URLSearchParams(searchParams);
        params.set('page', '1');
        if (term) {
            params.set('query', term);
        } else {
            params.delete('query');
        }
        startTransition(() => {
          replace(`${pathname}?${params.toString()}`);
        })
    }, 300);
    return (
        <>
            {isPending && <span>loading...</span>}
            <Input
                type="text" 
                placeholder="Search" 
                className="w-full h-12" 
                onChange={(e) => {
                    handleSearch(e.target.value);
                }}
                defaultValue={searchParams.get('query')?.toString()}
            />
        </>
    )
}
View full answer

11 Replies

@Yellowstripe scad ts export default function Search() { const searchParams = useSearchParams(); const { replace } = useRouter(); const pathname = usePathname(); const handleSearch = useDebouncedCallback((term) => { const params = new URLSearchParams(searchParams); params.set('page', '1'); if (term) { params.set('query', term); } else { params.delete('query'); } replace(`${pathname}?${params.toString()}`); }, 300); return ( <> <Input type="text" placeholder="Search" className="w-full h-12" onChange={(e) => { handleSearch(e.target.value); }} defaultValue={searchParams.get('query')?.toString()} /> </> ) } I want to add a loader, which is the component <Loader /> I have imported. I'm not sure how to make that work.
export default function Search() {
    const searchParams = useSearchParams();
    const { replace } = useRouter();
    const pathname = usePathname();
    const [isPending, startTransition] = useTransition()
    const handleSearch = useDebouncedCallback((term) => {
        const params = new URLSearchParams(searchParams);
        params.set('page', '1');
        if (term) {
            params.set('query', term);
        } else {
            params.delete('query');
        }
        startTransition(() => {
          replace(`${pathname}?${params.toString()}`);
        })
    }, 300);
    return (
        <>
            {isPending && <span>loading...</span>}
            <Input
                type="text" 
                placeholder="Search" 
                className="w-full h-12" 
                onChange={(e) => {
                    handleSearch(e.target.value);
                }}
                defaultValue={searchParams.get('query')?.toString()}
            />
        </>
    )
}
Answer
you can do it with useTransition hook
@Yellowstripe scad like it is loading if the user isnt done typing
could you show the code you have now?
Yellowstripe scadOP
"use client"
import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import { Input } from "./ui/input"
import { useDebouncedCallback } from 'use-debounce';
import { useState, useTransition } from 'react';
import Loading from './Loading';

export default function Search() {
    const searchParams = useSearchParams();
    const { replace } = useRouter();
    const pathname = usePathname();
    const [isPending, startTransition] = useTransition()
    const handleSearch = useDebouncedCallback((term) => {
        const params = new URLSearchParams(searchParams);
        params.set('page', '1');
        if (term) {
            params.set('query', term);
        } else {
            params.delete('query');
        }
        startTransition(() => {
            replace(`${pathname}?${params.toString()}`);
        })
    }, 300);
    return (
        <>
            {isPending && <Loading/>}
            <Input
                type="text" 
                placeholder="Search" 
                className="w-full h-12" 
                onChange={(e) => {
                    handleSearch(e.target.value);
                }}
                defaultValue={searchParams.get('query')?.toString()}
            />
        </>
    )
}
@Ray
what do you mean laggy / flickery?
Yellowstripe scadOP
if I type something into the search bar, quickly delete it and type something else the entire search bar lags. also, every letter I add it starts loading. I want to make it so it only loads when it detects typing stop if possible
@Ray try to increase the debounce time
Yellowstripe scadOP
worked! thank you!