Next.js Discord

Discord Forum

Infinite loop - useEffect, router, debounce

Unanswered
Barbary Lion posted this in #help-forum
Open in Discord
Barbary LionOP
I've been stuck on this for an hour 💀
Any ideas what is going wrong?

11 Replies

Barbary LionOP
'use client';

// import { useDebounce } from 'use-debounce';
import { Input } from '../ui/input';
import { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';

const useDebounce = (value: string, delay: number) => {
    console.table([`Debouncing: ${value}`, value]);
    const [debouncedValue, setDebouncedValue] = useState(value);

    useEffect(() => {
        const handler = setTimeout(() => setDebouncedValue(value), delay);

        return () => clearTimeout(handler);
    }, [value, delay]);

    return debouncedValue;
};

export function SearchBar({ search }: { search?: string }) {
    const router = useRouter();
    const [text, setText] = useState(search || '');
    const query = useDebounce(text, 300);

    useEffect(() => {
        if (!query || query === '') {
            router.push('/add');
        } else {
            router.push(`/add?search=${query}`);
        }
    }, [router, query]);

    const onChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
        setText(e.target.value);
    };

    return (
        <Input
            value={text}
            placeholder="Search song on Spotify"
            id={'search'}
            onChange={onChangeHandler}
        />
    );
}
I've tried my own debounce hook to check if it was an issue with the useDebounce
The strange thing is that it doesn't always happen, I haven't found bulletproof way to replicate it
⚠️ Epilespy warning ⚠️
Barbary LionOP
Note to myself: Never trust blindly YouTubers 🤦‍♂️
Using double useEffect smelled fishy, even more with the router as a dependency... and calling router.push() inside it
My new code:
'use client';

import { useDebouncedCallback } from 'use-debounce';
import { Input } from '../ui/input';
import { useRouter } from 'next/navigation';

export function SearchBar({ search }: { search?: string }) {
    const router = useRouter();

    const debounced = useDebouncedCallback((value) => {
        router.push(`/add?search=${value}`);
    }, 500);

    const onChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
        debounced(e.target.value);
    };

    return (
        <Input
            defaultValue={search}
            placeholder="Search song on Spotify"
            id={'search'}
            onChange={onChangeHandler}
        />
    );
}
I will add the correct way to URL encode the params
Definitely not perfect.. I'm loosing focus on the input now 😦
but at least I won't have an epillespy
or kill my Vercel bandwidth in a few hours