时间延迟后开始间隔并在按钮释放/反应时停止

Start interval after time delay and stop on button release / React

我正在尝试在 React 中构建一个简单的 plus/minus-control。单击加号或减号(由 onMouseDown 触发)时,值应按定义的步长更改,按住按钮时,值应在指定的延迟后按指定的间隔 in-/decrease。释放按钮时 (onMouseUp),间隔应停止。

下面的代码在 onMouseDown 上运行正常并保持,但是当我点击按钮时,间隔无论如何都会开始。我看到我需要确保在间隔开始之前按钮仍然处于按下状态,但我该如何实现呢?感谢您的任何见解。

let plusTimer = useRef(null);

const increment = () => {
  setMyValue(prev => prev + myStep);
  setTimeout(() => {
    plusTimer.current = setInterval(
      () => setMyValue(prev => prev + myStep),
      100
    );
  }, 500);
};

const intervalClear = () => {
  clearInterval(plusTimer.current);
};

我想我会让代码自己说话:

const {useCallback, useEffect, useState} = React;

const CASCADE_DELAY_MS = 1000;
const CASCADE_INTERVAL_MS = 100;

function useDelayedCascadeUpdate(intervalTime, delay, step, callback) {
  const [started, setStarted] = useState(false);
  const [running, setRunning] = useState(false);
  const update = useCallback(() => callback((count) => count + step), [
    callback,
    step
  ]);
  const handler = useCallback(() => {
    update();
    setStarted(true);
  }, [update, setStarted]);
  const reset = useCallback(() => {
    setStarted(false);
    setRunning(false);
  }, [setStarted, setRunning]);

  useEffect(() => {
    if (started) {
      const handler = setTimeout(() => setRunning(true), delay);
      return () => {
        clearTimeout(handler);
      };
    }
  }, [started, setRunning, delay]);
  useEffect(() => {
    if (running) {
      const handler = setInterval(update, intervalTime);
      return () => {
        clearInterval(handler);
      };
    }
  }, [running, update, intervalTime]);

  return [handler, reset];
}

function App() {
  const [count, setCount] = useState(0);
  const [incrementHandler, incrementReset] = useDelayedCascadeUpdate(
    CASCADE_INTERVAL_MS,
    CASCADE_DELAY_MS,
    1,
    setCount
  );
  const [decrementHandler, decrementReset] = useDelayedCascadeUpdate(
    CASCADE_INTERVAL_MS,
    CASCADE_DELAY_MS,
    -1,
    setCount
  );

  return (
    <div>
      <div>{count}</div>
      <button onMouseDown={incrementHandler} onMouseUp={incrementReset}>
        +
      </button>
      <button onMouseDown={decrementHandler} onMouseUp={decrementReset}>
        -
      </button>
    </div>
  );
}

ReactDOM.render(<App />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>