我有一个按钮,当用户单击它时会增加计数器,但如果用户单击速度非常快,我想延迟更新过程

问题描述 投票:0回答:3

我有一个按钮,当用户单击它时,它会使用 useState 挂钩来增加计数器,但我想知道是否有一种方法可以在用户快速单击按钮时将状态更新延迟 0.5 秒,然后更新计数器一次。例如,当用户每秒单击按钮 1 次时,计数器将立即更新。但如果用户在一秒内点击超过3次,状态不会立即更新,只有当用户停止快速点击时才会更新计数器。计数器将更新为延迟期间的点击次数。我尝试使用 setTimeOut 但没有成功。这个有钩子吗?

function App() {
   // State to store count value
   const [count, setCount] = useState(0);


   
   // Function to increment count by 1
   const incrementCount = () => {
     // Update state with incremented value
     setCount((prev)=>{
      return prev+1
     });
   };
   return (
     <div className="app">
       <button onClick={incrementCount}>Click Here</button>
       {count}
     </div>
   );
}
javascript reactjs
3个回答
4
投票

您需要应用Javascript Throttle功能。 Debounce 在这里并不是一个理想的解决方案,因为使用 Debounce,即使在第一次单击之后,用户也必须等待一段时间(延迟)才能执行。您想要的是,第一次点击计数器应该递增,但之后如果用户点击太快,则应该不会发生,直到一些延迟,这就是 Throttle 函数提供的。

还需要注意的是,要在 React 应用程序中使用 Throttle 或 Debounce,您将需要一个额外的钩子,即 useCallback,它不会在每次重新渲染时重新定义函数并提供一个记忆函数。

更多关于 Throttle 和 Debounce 之间的区别:https://stackoverflow.com/questions/25991367/difference- Between-throtdling-and-debouncing-a-function#:~:text=Throttle%3A%20the%20original%20function %20will,函数%20after%20a%20指定%20period.

让我们看一下代码:

import { useState, useCallback } from "react";

function App() {
  // State to store count value
  const [count, setCount] = useState(0);

  // Throttle Function
  const throttle = (func, limit = 1000) => {
    let inThrottle = null;
    return (...args) => {
      if (!inThrottle) {
        func.apply(this, args);
        inThrottle = true;
        setTimeout(() => (inThrottle = false), limit);
      }
    };
  };

  // Function to increment count by 1
  const incrementCount = useCallback(
    throttle(() => {
      // Update state with incremented value
      setCount((prev) => {
        return prev + 1;
      });
    }, 1000),
    []
  );

  return (
    <div className="app">
      <button onClick={incrementCount}>Click Here</button>
      {count}
    </div>
  );
}

export default App;

1
投票

这是纯粹的临时实现。我只是尝试使用两个状态变量和简单的实现。基本上,

  • 首先,在初始单击时,我立即执行计数变量 1。然后,每次点击后,将需要 1 秒来更新计数状态。
  • 然后,我在 setTimeout() 方法中放置了一个 if 块,即如果当前计数值与先前计数值之间的差为 1,则计数变量将更新。检查是因为每次单击时计数变量都会快速增加。所以,这个条件就成为了障碍。

import { useState } from "react";

function App() {
  // State to store count value
  const [count, setCount] = useState(0);
  const [prevCount, setPrevCount] = useState(0);

  // Function to increment count by 1
  const incrementCount = () => {

      setPrevCount(count);
      if(count === 0) setCount(1);
      setTimeout(() => {        
        if(count - prevCount === 1) {
          setCount(prev => prev + 1);
        }
      }, 1000);
      
      
  };

  return (
    <div className="app">
      <button onClick={incrementCount}>Click Here</button>
      {count}
    </div>
  );
}

export default App;


0
投票

这是我对这个问题的另一个答案,即去抖技术

Debounce是一种等待一定时间才能再次调用函数的技术。

在下面,您可以看到如何在 javaScript 中实现 debounce。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="src/style.css">
  </head>
  <body>
    <button id="button">click here</button>
    <div>
      <h1 id="countValue">count: 0<h1>
    <div>

    <script src="src/script.js"></script>
  </body>
</html>
const btn = document.getElementById('button');
const cnt = document.getElementById('countValue');
let count = 0;

const debounce = (fn, delay) => {
  let timeoutId;

  return function (...args) {
    clearInterval(timeoutId);
    timeoutId = setTimeout(() => {
      fn(...args);
    }, delay);
  }
}

const doCount = () => {
  console.log(`count: ${count}`);
  count = count + 1;
  cnt.innerHTML = `count: ${count}`;
}

btn.addEventListener("click", debounce(doCount, 500));
© www.soinside.com 2019 - 2024. All rights reserved.