1

I can not figure out why my onChange event listener is not accepting the last character in my form. (See image and console.log) onChange Issue

I have read the article on the react website on forms https://reactjs.org/docs/forms.html and I have also looked at the post onChange in React doesn't capture the last character of text

but still can not seem to find the answer.

Here is my code:

import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; /*stop clicking ability after clicking a problem (prevent default) and enable it when submit is done.*/ /* let btnStyle = { backgroundColor: 'green' } */ /*we also changed onClick={() => props.onClick()} to just onClick={props.onClick}, as passing the function down is enough for our example. Note that onClick={props.onClick()} would not work because it would call props.onClick immediately instead of passing it down.*/ class Square extends React.Component { render() { return ( <button className="square" onClick = {this.props.onClick} style = {{backgroundColor: this.props.backgroundColor}}> {this.props.value} {this.props.txt} </button> ); } } class Board extends React.Component { constructor(props) { super(props); this.state = { squares: Array(25).fill(null), xIsNext: true, squaresColor: Array(25).fill('null'), num1: generateRandomNumber(), num2: generateRandomNumber(), ans: function(a,b){return(a * b);}, sqTxt: Array(25).fill(null) }; //this.handleAnswer = this.handleAnswer.bind(this); } handleClick(i) { const squares = this.state.squares.slice(); // makes a mutable copy of the array const squaresColor = this.state.squaresColor.slice(); // makes a mutable copy of the array const sqTxt = this.state.sqTxt.slice(); // makes a mutable copy of the array if (/* calculateWinner(squares) || */ squares[i]) { return; } squaresColor[i] = 'blue'; sqTxt[i] = <input onChange = {(e,i) => this.handleAnswer(e, i)} className = 'answer-input' type = 'text' name = 'answer' />; this.setState({ squares: squares, xIsNext: !this.state.xIsNext, squaresColor: squaresColor, /* num1: generateRandomNumber(), num2: generateRandomNumber(), */ sqTxt: sqTxt }); squares[i] = this.state.num1 + ' X ' + this.state.num2; } /*When an event is invoked, it will be passed an event object as it's first argument. You can name evt whatever you like. Common names are e evt and event.*/ handleAnswer(e, i) { const userAnswer = parseInt(e.target.value, 10); const num1 = this.state.num1; const num2 = this.state.num2; const correctAnswer = num1 * num2; const squaresColor = this.state.squaresColor.slice(); // makes a mutable copy of the array console.log('num1: ' + num1); console.log('num2: ' + num2); console.log('userAnswer: ' + userAnswer); console.log('correctAnswer: ' + correctAnswer) squaresColor[i] = 'purple'; this.setState({ squaresColor: squaresColor }) if(userAnswer === correctAnswer) { this.setState({squaresColor: squaresColor}); console.log('correct'); squaresColor[i] = 'green'; } else { console.log('incorrect'); } //create new numbers for next problem this.setState({num1: generateRandomNumber(), num2: generateRandomNumber()}); } renderSquare(i) { return ( <Square value={this.state.squares[i]} onClick = {() => this.handleClick(i)} backgroundColor = {this.state.squaresColor[i]} txt = {this.state.sqTxt[i]} /> ); } render() { return ( <div className = 'all-rows'> <div className="board-row"> {this.renderSquare(0)} {this.renderSquare(1)} {this.renderSquare(2)} {this.renderSquare(3)} {this.renderSquare(4)} </div> <div className="board-row"> {this.renderSquare(5)} {this.renderSquare(6)} {this.renderSquare(7)} {this.renderSquare(8)} {this.renderSquare(9)} </div> <div className="board-row"> {this.renderSquare(10)} {this.renderSquare(11)} {this.renderSquare(12)} {this.renderSquare(13)} {this.renderSquare(14)} </div> <div className="board-row"> {this.renderSquare(15)} {this.renderSquare(16)} {this.renderSquare(17)} {this.renderSquare(18)} {this.renderSquare(19)} </div> <div className="board-row"> {this.renderSquare(20)} {this.renderSquare(21)} {this.renderSquare(22)} {this.renderSquare(23)} {this.renderSquare(24)} </div> </div> ); } } class Game extends React.Component { render() { return ( <div className="game"> <div className="gxame-board"> <Board /> </div> <div className="game-info"> </div> </div> ); } } ReactDOM.render( <Game />, document.getElementById('root') ); function generateRandomNumber() { return Math.floor(Math.random() * 10); } 

1 Answer 1

1

The problem is you're using onChange. onChange mean that if you change something it'll send an event. For example in your code:
You've change input to 18, but the first input change was 1 before you type the next 8, so when you type 18, it will send 2 event onChange
And in the last line of handleAnswer, your code:

this.setState({num1: generateRandomNumber(), num2: generateRandomNumber()}) 

It means, after you've input 1 the state of num 1 & num 2 are changed.
I suggest to you that, you have to move this.setState({num1: generateRandomNumber(), num2: generateRandomNumber()}); in the conditional if, when user have input a right answer, it will change the state of num1 & num2.
Another suggestion from me, you can try this method
to call onChange event after pressing Enter key

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.