0

I have an AutoComplete component and by default it has no data to display. When a user types something it will load data dynamically. But I want this to be done when user stops typing, not each time enters something quickly. So I wait for 1500 miliseconds and then check if string has changed or not. But the code doesn't work the way I expected.

const dispatch = useDispatch();
const [searchStr, setSearchStr] = useState(null);

function handleChange(event) {
    const str = event.target.value.toLowerCase();

    if (str.length < 2) return;

    setSearchStr(str);

    setTimeout(() => {
      // str never equals searchStr
      console.log(str, searchStr)
      if(str === searchStr) {
         dispatch(doSearch(searchStr));
      }
    }, 1500);
}
Er.Se
  • 461
  • 3
  • 11

1 Answers1

0

You have two problems in your code.

1- setState is run asynchronously so setSearchStr doesn't instantly change the value of searchStr

2- Each time the input changes, a new setTimeout is created so after 1500ms from the first character typing, it will lose its effect. The thing you're going to do is called debouncing. The solution is to clear the previous setTimeouts before creating a new one:

let timer; // =========> HERE

function MyComponent() {
  const dispatch = useDispatch();
  const [searchStr, setSearchStr] = useState(null);

  function handleChange(event) {
    const str = event.target.value.toLowerCase();

    if (str.length < 2) return;

    setSearchStr(str);

    clearTimeout(timer); // =========> HERE

    timer = setTimeout(() => {
       dispatch(doSearch(str));
    }, 1500);
  }
}

If you insist on saving the search value in a stateful variable, you can use useEffect:

let timer; // =========> HERE

function MyComponent() {
  const dispatch = useDispatch();
  const [searchStr, setSearchStr] = useState(null);

  function handleChange(event) {
    const str = event.target.value.toLowerCase();

    setSearchStr(str);
  }

  useEffect(() => {
    if (searchStr.length < 2) return;

    clearTimeout(timer);

    timer = setTimeout(() => {
       dispatch(doSearch(searchStr));
    }, 1500);
  }, [searchStr])
}
pouria
  • 949
  • 8
  • 21