Persistent bug - spamming enter in React app

I am working on a React project that is a math fact practice app. I made a toy version to work on a specific bug I can’t figure out. That version is here: https://codepen.io/dkane47/pen/XWGoVaE

Here is the issue. When a user typed an answer and hit enter, the app functioned well. When a user typed an answer and spammed enter over and over again, the app would behave erratically and skip through a bunch of problems.

Then I added the lodash library and used the debounce function. I initially thought it solved the problem, and it seemed like spamming enter no longer caused erratic behavior. However, there is a setTimeout of 1000 milliseconds for a “correct” message to appear briefly before moving to the next problem. If the user submits a correct answer, hits enter, pauses momentarily, then spams enter as the setTimeout is ending, it causes erratic behavior again. I want to ensure that the following series of actions occurs:

User hits enter. No matter the number of times enter is pressed, the app triggers a state update to display a message, then pauses for 1000 milliseconds.

1000 milliseconds is over. The app triggers a state update to display a new problem. Any more hits on the enter key do nothing until the new problem is displayed.

I have tried a number of other solutions and nothing has worked. It seems like there is some irregularity in the timing of state updates that makes this a challenging problem to solve. Any ideas?

It sounds like you’re dealing with an issue related to debounce and handling user input.

import React, { useState, useEffect } from “react”;
import _ from “lodash”;

function App() {
const [inputValue, setInputValue] = useState(“”);
const [currentProblem, setCurrentProblem] = useState(generateProblem());
const [correctMessage, setCorrectMessage] = useState(false);

function generateProblem() {
const num1 = Math.floor(Math.random() * 10) + 1;
const num2 = Math.floor(Math.random() * 10) + 1;
return {
num1,
num2,
answer: num1 + num2
};
}

useEffect(() => {
document.addEventListener(“keydown”, handleKeyPress);
return () => {
document.removeEventListener(“keydown”, handleKeyPress);
};
}, [currentProblem]);

const handleKeyPress = _.debounce((e) => {
if (e.key === “Enter” && !correctMessage) {
if (parseInt(inputValue) === currentProblem.answer) {
setCorrectMessage(true);
setTimeout(() => {
setCurrentProblem(generateProblem());
setInputValue(“”);
setCorrectMessage(false);
}, 1000);
}
}
}, 500, { leading: true, trailing: false });

return (


Math Fact Practice



{currentProblem.num1} + {currentProblem.num2} ={" "}
<input
type=“number”
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
disabled={correctMessage}
/>
{correctMessage && Correct!}


);
}

export default App;

here is example of modified code may be it will help for you to solve this issue.
In this modified version, I added a correctMessage state to track whether the correct message is being displayed. While the correct message is being displayed, the input field is disabled, preventing further user input.

Nice app @dkane47.

I think the issue is not related to debouncing because debouncing is used for decreasing function calls, but you want to stop the user submit solutions in a condition that is the correct phase.

In your current logic, the user can submit new solutions even if the current solution is correct, so the app creates several timeouts in the one-second frame. As a result, after one second is passed, the app skips a bunch of problems. You should prevent the user from submitting solutions when the current solution is correct.

As a solution, I’ve removed the debounce logic from your code and added an if statement to the beginning of the checkAnswer function.

function checkAnswer() {
  if (feedback === "Correct") return;

  /* ... */
}

So, if the feedback equals Correct, it doesn’t evaluate the solution. Thus even if the user clicks the button or presses Enter, the app waits for one second.

Happy coding!

This works perfectly, and I love how simple it is. I was going down a rabbit hole of using a form library and different tools in lodash and this is much better. Thank you!

1 Like

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.