首页 > 解决方案 > React hooks - 防止 useEffect 更新太快

问题描述

我正在制作一个日期选择器组件。有三个“刻度盘”,分别代表天、月和年,通过在列 div 内拖动鼠标来移动它们。它工作得很好,除了它更新得非常快而且整个事情进展得太快了。如何确保它仅按设定的时间间隔更新?

我的 useEffect 代码是:

    useEffect(() => {
            if (mouseState.mouseIsDown && mouseState.dateField === 'year') {
                getYear();
            } else if (date) {
                setNewStartDate();
            }

            if (mouseState.mouseIsDown && mouseState.dateField === 'month') {
                getMonth();
            } else if (date) {
                setNewStartDate();
            }

            if (mouseState.mouseIsDown && mouseState.dateField === 'day') {
                getDay();
            } else if (date) {
                setNewStartDate();
            }
        },
        [ mouseState.mouseIsDown, mouseState.dateField, endPositionYYear, endPositionYMonth, endPositionYDay ]
    );

我的 getYear 函数是这样的:

    const getYear = () => {
            getPositions('year');
            if (startDate.getFullYear() >= 1911 || (endPositionYYear < 0 && startDate.getFullYear() === 1911)) {
                if (endPositionYYear > prevEndPositionYYear) {
                    setMyDate(new Date(year - 1, month, day));
                } else {
                    setMyDate(new Date(year + 1, month, day));
                }
            } else if (startDate.getFullYear() < 1911 && endPositionYYear > 0) {
                setMyDate(new Date(year + Math.round(endPositionYYear / 10), month, day));
            }
        };

如果我在 getYear 函数期间设置 Timeouts,useEffect 钩子会从 mouseState.mouseIsDown 接收新的 Y 位置坐标,它会在鼠标左键按下时存储鼠标的 Y 坐标,在超时过去之前,函数调用将被最新的 getYear 调用覆盖?我认为?

有什么方法可以确保每 500 毫秒才调用一次 getYear 吗?

标签: reactjssettimeoutsetinterval

解决方案


您可以根据自己的需要进行改进。

// 0 is no limit
function useDebounce(callFn, callCount = 0 , time = 1000){
  const timeout = useRef(); // to clear interval in anywhere
  const counter = useRef(0);


  function clear(){
    timeout.current && clearInterval(timeout.current);
    counter.current = 0;
  }

  useEffect(() => {
    timeout.current = setInterval(() => {
      callFn(counter.current++); // pass call-count, it may be useful
      if(callCount > 0 && counter.current == callCount){
        timeout.current && clearInterval(timeout.current);
      }
    }, time);
    return clear
  }, []);

  return useCallback(() => clear(), []);
}

推荐阅读