Youssef
Youssef

Reputation: 165

prevent multiple refetch with apollo useLazyQuery

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

Answers (1)

wdsrocha
wdsrocha

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

Related Questions