Reputation: 165
the intended behaviour
I have a search input , when the user type a word , I would like to wait for 1s before refetching data using appolo useLazyQuery. however if before the 1s the user start typing again the timer should be reset.
so I am using setTimeOut and clearTimeout however I noticed that appollo send a request for every stroke.
is there a way to prevent multiple refetching, and only send a request after 1s when the user stop typing
import React, { useState } from 'react'
import { useLazyQuery } from '@apollo/react-hooks'
import {GET_BUSINESSES} from '../../../qraphQl/businessType'
const SearchTool = () => {
const [name, setName] = useState('')
const [busSug, setBusSug] = useState({busSug:[], showBusSug: false})
// prevent sending many hhtp request
const [getBusiness , { loading , data, error }] = useLazyQuery(GET_BUSINESSES)
let typingWaitTimer = null
const handleNameChange = (event) => {
clearTimeout(typingWaitTimer)
const val = event.target.value
setName(()=> val)
typingWaitTimer = setTimeout(() => getBusiness( {variables: { query: name }} ) , 1000)
}
Upvotes: 1
Views: 2548
Reputation: 57
You could use an effect hook in a way that for each timeout set, the last one will be cleared/overwritten.
Take a look at the following snippet: you can verify that it will only log to console when you stop to type for a whole 1s.
import React, { useEffect, useState } from "react";
// mocked those just for demonstration, but it
// should work with the real graphql hook. Feel
// free to ignore this part
const GET_BUSINESSES = "your graphql file";
const useLazyQuery = () => {
return [({ variables: { query } }) => console.log(`query: ${query}`)];
};
const DELAY_IN_MS = 1000;
export default function App() {
const [name, setName] = useState("");
// omitting { data, error, loading } here just
// because they aren't used in the example
const [getBusiness] = useLazyQuery(GET_BUSINESSES);
// every time `name` changes, this hook will be
// triggered
useEffect(() => {
const handler = setTimeout(() => {
getBusiness({ variables: { query: name } });
}, DELAY_IN_MS);
// this will make sure that the timeout will
// be cleared if the effect gets called again
return () => {
clearTimeout(handler);
};
}, [name, getBusiness]);
const handleNameChange = (event) => {
setName(event.target.value);
};
return <input value={name} onChange={handleNameChange} />;
}
By the way, the name for this short interval before calling a function is called debounce. This blog post makes a good job explaining how to implement debounce with React hooks, and my example is based on it.
Upvotes: 2