2

Here is my repo https://github.com/extrapractice/lambda-calculator/tree/revised

What is going on is when I am using a react hook for useState, it works fine, but however, I set up an event listener on useEffect for when a key is pressed (its a calculator) but for some reason once the key is pressed and the event is fired, the react state is undefined?

Why is this happening and how would I correct this?

const Calculator = (props) => {
const [ display, setDisplay ] = useState('');

useEffect(() => {
    window.addEventListener('keydown', handlekeyDown);
    // window.addEventListener('keydown', handleEquals);
    return () => {
        window.addEventListener('keydown', handlekeyDown);
        // window.addEventListener('keydown', handleEquals);
    };
}, []);

function handlekeyDown(e) {
    e.preventDefault();
    const current = e.key;
    const values = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '+', '-', '*', '/'];
    if (values.includes(current)) {
        let value = current;
        setDisplay((prev) => prev + value);
    }
}

 function handleEquals(e) {
    const value = e.key
    console.log(display)
    if (value === '=') {
        const solution = math.evaluate(display)
        const histEntry = { problem: display, solution: solution };
        props.setHistory((prev) => [ ...prev, histEntry ]);
        setDisplay(solution);
    }
}

function addToString(e) {
    console.log(e.target)
    let value = e.target.value;
    if (value === '=') {
        const histEntry = { problem: display, solution: math.evaluate(display) };
        props.setHistory((prev) => [ ...prev, histEntry ]);
        setDisplay(math.evaluate(display));
    } else {
        setDisplay((prev) => prev + value);
    }
}
Michael
  • 127
  • 1
  • 13
  • 1
    Mind sharing *all* of the component code so it is easier to see what, where and when your `display` state is updated? Also, include the code for `math.evaluate`. FYI, you have a mistake in the return function of the effect, it should remove the event listener. – Drew Reese Jan 05 '20 at 04:39
  • 1
    I looked in your repo for the whole component code, and also see `math.evaluate` is `math.js` and returns a number instead of a string. Trying to repro your issue but not successful yet. [codesandbox](https://codesandbox.io/s/amazing-elgamal-74h16?expanddevtools=1&fontsize=14&hidenavigation=1&moduleview=1) – Drew Reese Jan 05 '20 at 05:07
  • Nice catch about the event listener, the issue is solved and my solution is below, any idea why this works like this? – Michael Jan 06 '20 at 05:32
  • Not really, no, as doing so would only trigger the effect each time `handlekeyDown` function was updated. Maybe it is because you define `handlekeyDown` *after* the effect, thus it is triggered with undefined, then once it becomes defined it's triggered again (now, since in dependency array). Doesn't seem likely this is the case though. – Drew Reese Jan 06 '20 at 05:41
  • Interesting, I am newer to react hooks, so this is kind one of my introduction projects just to get familiar with them... will indeed try to look deeper into the code and see why it only works when included in the dependency array, thanks for your help Drew. – Michael Jan 06 '20 at 05:56
  • Adding/removing the event listener and handling the key events appears to function as I'd expect in the codesandbox I linked, so I'm wondering if there's a logic bug elsewhere in your code around updating state (that's why I looked at the math.js code). I didn't dig too deeply for any overt errors though since first step of fixing bugs is having a solid repro. Glad it is working for you now, hopefully it doesn't manifest differently later. – Drew Reese Jan 06 '20 at 06:01
  • This is answered here: https://stackoverflow.com/questions/55265255/react-usestate-hook-event-handler-using-initial-state – Steve Jul 06 '21 at 21:06

1 Answers1

3

So what fixed this was adding the handleKeydown into the dependency array of the useEffect. The exact reason of why this is the case I have not narrowed 100% but I have a pretty solid idea.

Michael
  • 127
  • 1
  • 13