1

I have a valid code, which runs when I change some text

import React, { useState } from "react";


const onChange = async ({ target: { value, name } }) => {
    setErrors({ ...errors, [name]: false });
    setUserData({ ...userData, [name]: value });

    if (name === "address") {
      const res = await searchAddress(value);
      if (res.success) {
        setAddressList(res?.results?.matches || []);
      }
    }
  };

How can I execute searchAddress only if text change happened and previous call was later than 5 seconds?

swor
  • 751
  • 3
  • 8
  • 21

3 Answers3

1

You can use debouce for this.

import React, { useState, useCallback } from "react";



const onChange = async ({ target: { value, name } }) => {
  setErrors({ ...errors, [name]: false });
  setUserData({ ...userData, [name]: value });

const searchAddress = useCallback(debounce(async (value)=> await searchAddress(value), 5000), []);

  if (name === "address") {
    const res = await searchAddress(value);
    if (res.success) {
      setAddressList(res?.results?.matches || []);
    }
  }
};
folan
  • 215
  • 1
  • 8
  • 1
    are you sure that this code it's right? [you cannot use hooks outside a react function](https://www.freecodecamp.org/news/how-to-use-react-hooks-ef70894d9fd/#:~:text=You%20can%20not%20use%20hooks,appear%20in%20the%20component%20function.) and [rules of hooks](https://reactjs.org/docs/hooks-rules.html). Also, does it update the value inside the function? you have an empty dependency array. – Jorge Kunrath Apr 10 '21 at 20:03
0

You can use external library like lodash's throttle for this, but also achievable with a simple settimeout.

let timer; //declare the timer variable outside the component

const App = () => {
    ...declare useState here..

const onChange = async ({ target: { value, name } }) => {
    setErrors({ ...errors, [name]: false });
    setUserData({ ...userData, [name]: value });

    if (name === "address") {
      clearTimeout(timer) //clear the timeout on every change.
      timer = setTimeOut(() => { //create a timeout to the timer variable so u can clear it
      const res = await searchAddress(value);
      if (res.success) {
        setAddressList(res?.results?.matches || []);
      }
       }, 5000) 
    }
  };

   return .....
}

If you are doing autocomplete, 5000 is a really long time and not good for user experience, a 200-500ms timeout would be nice since the timeout is cleared on every keystroke.

Using a 200-500 timeout means the API will only be fetched if the user paused typing for 200-500ms instead of every keystroke.

Someone Special
  • 12,479
  • 7
  • 45
  • 76
0

In my case I use a rxjs Subscription to request the data every half second.

HTML

(input)="onFilterChange()"

TS

onFilterChange() {
        // Init the subscription when the user is typing
        this.subscription.unsubscribe()
        this.subscription = interval(500).subscribe(() => {
            this.subscription.unsubscribe()
            this.loadData()
        })
}
Johana Lopez 1327
  • 165
  • 1
  • 3
  • 14