0

I am currently writing a 2048 game which detects user's keyboard input and then change state of the corresponding direction; but I failed to change the state. I use this as a reference to capture the input command. React onKeyDown/onKeyUp events on non-input elements Then setting up a string called keyValue to store the keyboard input's string value and update keyValue in my addEventListener. But I failed to setState by the keyValue in my componentDidMount. My code is as follow. I also tried to setState in my addEventListner earlier but it failed as well. Could anyone help? Thanks.

constructor(props) {
        super(props);
        this.state = {
            board: Array(4).fill().map(x => Array(4).fill(0)),
            score: 0,
            end: false,
            emptySpace: true,
            left: false,
            right: false,
            up: false,
            down: false
        };
    }

   componentDidMount() {
        var cmdDown = false;
        var keyValue = "";
        document.body.addEventListener('keydown', function (event) {
            var key = event.keyCode || event.charCode || 0;
            if ([37, 38, 39, 40].indexOf(key) !== -1) {
                cmdDown = true;
                if ([37].indexOf(key) !== -1) {
                    keyValue = "ArrowLeft";
                } else if ([38].indexOf(key) !== -1) {
                    keyValue = "ArrowUp";
                } else if ([39].indexOf(key) !== -1) {
                    keyValue = "ArrowRight";
                } else if ([40].indexOf(key) !== 1) {
                    keyValue = "ArrowDown"
                }
            }
            console.log(keyValue);
            console.log('CMD DOWN: ' + cmdDown.toString());
        });

        document.body.addEventListener('keyup', function (event) {
            var key = event.keyCode || event.charCode || 0;
            if ([37, 38, 39, 40].indexOf(key) !== -1) {
                cmdDown = false;
            }
            console.log('CMD DOWN: ' + cmdDown.toString());
        });
        if (keyValue === "ArrowUp") {
            this.setState({ up: true });
            this.setState({ down: false });
            this.setState({ left: false });
            this.setState({ right: false });
        } else if (keyValue === "ArrowDown") {
            this.setState({ up: false });
            this.setState({ down: true });
            this.setState({ left: false });
            this.setState({ right: false });
        } else if (keyValue === "ArrowLeft") {
            this.setState({ up: false });
            this.setState({ down: false });
            this.setState({ left: true });
            this.setState({ right: false });
        } else if (keyValue === "ArrowRight") {
            this.setState({ up: false });
            this.setState({ down: false });
            this.setState({ left: false });
            this.setState({ right: true });
            console.log(this.state.right)
        }
    }

I wrote a function to printout my states. but inn the log it always print false. Why my state not getting update while render? Are there anything related to synchronization?

printDir = () => {
        console.log("up: " + this.state.up.toString());
        console.log("down: " + this.state.down.toString());
        console.log("left: " + this.state.left.toString());
        console.log("right: " + this.state.right.toString());
    }
 <button onClick = {this.printDir}>dir</button>

2 Answers2

0

If you want to use eventlistener, you have to use ref props to access DOM. For the example <div ref={this.divRef} ... and in componentDidMount() you can write this.divRef.current.addEventListener('keydown', ...)

0

There are two issues I can see in your snippet:

  1. Your if-else conditions for checking arrow keys are outside of listener setup which won't be triggered
  2. You use ES5 function syntax here, this object will refer to your function scope, not class scope. You might want to use ES6 arrow function syntax to avoid this object scope issue
Vincent
  • 16
  • 1