How to use anti-shake hooks in React
P粉497463473
P粉497463473 2024-01-28 22:15:30
0
2
433

import { useEffect, useState } from 'react';

export default function useDebounce(text: string, delay: number) {
  const [value, setValue] = useState('');

  useEffect(() => {
    const timerId = setTimeout(() => {
      setValue(text);
    }, delay);
    return () => {
      clearTimeout(timerId);
    };
  }, [text, delay]);
  return value;
}


I used to make and use useDebounce hooks. However, there are some issues with using useDebounce in a resize event. useDebounce hook must be run on top of the component because it uses useEffect internally. However, the resize function is set up to run on useEffect as shown below.

Also, the above code takes the value as a factor, but I think we need to receive it as a callback to use the code below.

  useEffect(() => {
    const handler = () => {
      if (liRef.current) setWidth(liRef.current.clientWidth);
    };

    window.addEventListener('resize', handler);
    return () => window.removeEventListener('resize', handler);
  }, []);

How to use the above code to take advantage of the existing useDebounce?

P粉497463473
P粉497463473

reply all(2)
P粉098417223

If you use the debounced function directly in the React component, it will not work because a new function will be created for each render. Instead, you can use this useDebounce hook:

function useDebounce(callback, delay) {
  const callbackRef = React.useRef(callback)
  React.useLayoutEffect(() => {
    callbackRef.current = callback
  })
  return React.useMemo(
    () => debounce((...args) => callbackRef.current(...args), delay),
    [delay],
  )
}

useRef ensures that it is the same function as the last one provided, and useLayoutEffect ensures that on every render, the reference to the function is updated.

For more information on this, see "Latest Reference" Pattern Reaction

P粉894008490

I think that instead of implementing debounce through useEffect, it is better to implement the debounce logic as a function.

useEffect Executed when the state referenced by deps changes. In other words, since it is a logic that is easily missed if you only follow the execution process, it is difficult to figure out which process this useEffect is derived from during later maintenance, and it is also difficult to debug.

Example

Customized debounce

function debounce(func, timeout = 300) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, timeout);
  };
}
function saveInput() {
  console.log('Saving data');
}
const processChange = debounce(() => saveInput());


If you use lodash, you can just import to use it.

Lodash Debounce

import { debounce } from 'lodash';
const debounceOnChange = debounce(() => {
  console.log("This is a debounce function");
}, 500);

Hope this helps :)

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template