反应挂钩-防止useEffect更新太快

时间:2020-02-27 20:07:58

标签: reactjs settimeout setinterval

我有一个正在做的日期选择器组件。通过在列div内拖动鼠标,可以移动3天,几天,几个月和几年的“拨号”。它工作得很好,除了它更新得非常快而且整个动作移动得太快之外。如何确保它仅按设置的时间间隔更新?

我的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函数期间设置了超时,则useEffect钩子会从mouseState.mouseIsDown接收新的Y位置坐标,该坐标存储超时之前的鼠标左键按下时(在超时之前)的Y坐标,并且函数调用会被对getYear的最新调用所覆盖吗?我觉得吗?

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

1 个答案:

答案 0 :(得分:1)

您可以根据需要进行改进。

// 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(), []);
}