简体   繁体   中英

react long press event for stopwatch

I've been struggling a lot with this question. Before creating this post here, I've searched throughout the community and I've seen so many solutions for long press events in React, but everyone of them solves just for a click button event.

I'm creating a stopwatch for Rubik's myself. What I need to do is the following steps:

  1. The user must hold spacebar for two seconds to be "good to go";
  2. Once the user is "good to go", at the moment he releases the spacebar, the stopwatch starts;
  3. Once he's done with the Rubik's, he presses the spacebar again to stop the stopwatch.

PS-1: If the stopwatch is not running and the user just presses the spacebar (does not hold it), nothing should happen! The stopwatch only starts if the user holds the spacebar for at least two seconds and then releases it.

Now, my problem is that all the events (start and stop) I should be looking at is under the "keydown" and "keyup" listeners in JavaScript. I've tried so many different solutions to manage the timeout native function in JS, but as I said, I should not do anything if the stopwatch is stopped and the user just presses the spacebar.

I've tried to use useState and useRef hook to control the timeout and to check if the spacebar was just pressed or it was long pressed. And again, my problem is not knowing how to manage it once these two events are under the "keydown" listener.

I hope you guys can help me, it would mean a lot!

Thank you in advance.

PS-2: I'm using TypeScript!

If you're only wanting the event to fire when the spacebar is released, why don't you just use a timestamp for reference? Something along the lines of:

const [timestamp, setTimestamp] = useState(0);

const spacebarPress = (e) => {
  if (e.keyCode !== 32) return; // exit if the key is not spacebar
  setTimestamp(Date.now());
}

const spacebarRelease = (e) => {
  if (e.keyCode !== 32) {
    return; // exit if the key is not spacebar
  }
  const pressed = timestamp, released = Date.now();
  setTimestamp(0); // no longer needed, reset for next press
  if (released - pressed < 2000)
    return; // less than 2 seconds have passed since pressing
  // ... your logic here, spacebar was pressed for two seconds.
}

I generally tend to avoid setTimeout where possible, IMO it's not very reliable and a pain to debug.

I'm trying to solve this problem using the following code:

  useEffect(() => {
    document.addEventListener("keydown", handleKeyDown);
    document.addEventListener("keyup", handleKeyUp);

    return () => {
      removeEventListener("keydown", handleKeyDown);
      removeEventListener("keyup", handleKeyUp);
    };
  }, []);

  const handleKeyDown = (e: KeyboardEvent) => {
    if (e.key !== " ") {
      return;
    }

    timeRef.current = Date.now();
    setTimestamp(Date.now());
  };

  const handleKeyUp = (e: KeyboardEvent) => {
    if (e.key !== " ") {
      return;
    }

    const pressed = timestamp;
    const released = Date.now();

    if (released - pressed < 2000) {
      return;
    }
  };

For some reason, timestamp state is always 0 (default state). I've tried using useRef instead, but it didn't work either.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM