3

I looked at this example of how to write a search field that only searches when the user stops typing. I made my own implementation with apollo client here:

const SEARCH_QUERY = gql`
    query Search($terms: [String]!) {
        search(terms: $terms) {
            id
            title
            desc
            imagePreview
        }
    }
`;

const Browse = () => {
    const [searchKeyword, setSearchKeyword] = useState("");
    const [searchQuery, { loading: searchLoading, error: searchError, data: searchData },] = useLazyQuery(SEARCH_QUERY, {
        variables: { terms: searchKeyword.split(" ") },
        fetchPolicy: "network-only",
    }); // get new courses by searched terms

    useEffect(
        () => {
            const delayDebounceFn = setTimeout(() => {
                console.log(searchKeyword);
                // Debounce only works first time. The function below gets called even when the above console.log isn't shown in the console.
                searchQuery();
            }, 3000);

            return () => clearTimeout(delayDebounceFn);
        },
        [searchKeyword]
    );

    return (
        <div>
            <input
                autoFocus
                type="text"
                autoComplete="off"
                placeholder="Search here..."
                onChange={(e) => setSearchKeyword(e.target.value)}
            />
            {searchLoading ? <p>Loading...</p> : searchData ? <Row items={searchData.search}/>}
        </div>
    );
};

It works fine, but only the first time. As soon as the first request has been sent the search keyword just gets updated immediately and sends a new request on every type. The most bizarre thing is that the console.log(searchKeyword) doesn't show up, but the searchQuery function is still getting called.

EDIT: I figured it out. The problem was that i was using a different variable every time in my UseLazyQuery (also described here on a github issue). All i had to do was change my query variables from this:

const [searchQuery, { loading, error, data}] = useLazyQuery(SEARCH_QUERY, {
        variables: { terms: searchKeyword.split(" ") },
        fetchPolicy: "network-only",
    }); // get new courses by searched terms

...to this:

const [searchQuery, { loading, error, data}] = useLazyQuery(SEARCH_QUERY, {
        variables: { terms: searchKeyword },
        fetchPolicy: "network-only",
    }); // get new courses by searched terms

I just ended up splitting the terms on the server instead of the client. Thanks for the help guys :).

Nikolai
  • 31
  • 3
  • What library is `useLazyQuery` from? – Hozeis Aug 16 '21 at 18:30
  • Im just asking because from what you're saying the function gets called after the first time on every re-render. Is it possible that `useLazyQuery` does not automatically call the query after its first initialization on re-renders? Something like that would have to be happening if `console.log` isn't being displayed. – Hozeis Aug 16 '21 at 18:32
  • 1
    @Hozeis it's from Apollo Client (https://www.apollographql.com/docs/react/api/react/hooks/#uselazyquery) – diogo.silva Aug 16 '21 at 18:33
  • @Hozeis I think the purpose of useLazyQuery is that it can be used after the first initialization (https://www.apollographql.com/docs/react/api/react/hooks/#uselazyquery). – Nikolai Aug 16 '21 at 18:37
  • @Hozeis Also the problem isn't with fetching the data, it's that the delayDebounceFn isn't working after searchQuery has been called the first time. – Nikolai Aug 16 '21 at 18:40
  • try typing and stoping. This will cause the first query request. Then type again and stop. This (with the error) would then make the request on every key. See if you still get an additional `console.log` – Hozeis Aug 16 '21 at 18:53
  • @Hozeis The weird thing is when i do that the console.log still waits the 3000ms from the timeout but searchQuery is called immediately (on every key press) – Nikolai Aug 16 '21 at 19:32
  • It might not be the debounce function. I have never used Apollo but try altering you code to work with refetch. https://www.apollographql.com/docs/react/data/queries/#refetching - Heres a SO awnser that shows `refetch` and `useLazyQuery` https://stackoverflow.com/a/62633101/4825796. I might be completely wrong do. – Hozeis Aug 16 '21 at 19:44
  • Can you write a clearTimeouut before calling timeout with a check, if exists and try. Because on every onchange function call it is initiating but not gets cleared until component unmount. You can refer to the first answer of your reference link. – Abhijit Sil Aug 16 '21 at 20:55

0 Answers0