Reputation: 2332
I am learning React and I am trying to update one component based on an input value. I have done this using html and vanilla JavaScript and it works. I am trying to implement the same functionality using React but I am having some challenges.
Here is my code in vanilla javascript:
index.html
<!DOCTYPE html>
<html lang="en">
<body>
<div>
<div>
<div>
<h2>Press button when you are ready to play</h2>
<input type="text" placeholder="Start typing..." id="word-input" autofocus>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
script.js
const wordInput = document.querySelector('#word-input');
const currentWord = document.querySelector('#current-word');
const words = [
'rock', 'paper', 'scissors', 'play'
];
displayWord(words)
wordInput.addEventListener('input', matchWords);
function displayWord(word) {
const Index = Math.floor(Math.random() * word.length);
currentWord.textContent = word[Index];
};
// match words
function matchWords() {
if(wordInput.value === currentWord.innerHTML) {
displayWord(words);
wordInput.value = '';
};
};
Here is what I have tried in React so far:
import React, { Component, createRef } from 'react'
export class About extends Component {
state = {
words: [
'rock', 'paper', 'scissors', 'play'
],
current_input: 'Start...',
current_word: 'break'
}
inputRef = createRef();
displayWord = (word) => {
const Index = Math.floor(Math.random() * word.length);
let rword = word[Index];
this.setState({
current_word: rword
})
};
matchWords = (e) => {
this.setState({
current_input: e.target.value
})
if(this.state.current_input === this.state.current_word) {
this.displayWord(this.state.words);
this.setState({
current_input: ''
})
this.inputRef.current.focus();
};
};
render() {
return (
<div>
<div>
<div>
<h2 id="current-word">{this.state.current_word}</h2>
<input ref={this.inputRef}
placeholder='start ..' onChange={this.matchWords} type="text" id="word-input" autoFocus />
</div>
</div>
</div>
)
}
}
export default About
It seems to work. However, the problem is it doesn't update after I type in the word - I have to attempt to delete the contents of the input box before I see a new word show up. Also, it doesn't automatically clear the contents and autofocus on the input box for me to type the new word. I would like to know what I am missing and also as far as best practices go, is this the best or 'right' way to do something like this using React. Thanks!
Upvotes: 0
Views: 1254
Reputation: 383
class About extends Component {
state = {
tmp: "",
words: ["rock", "paper", "scissors", "play"],
current_input: "",
current_word: "break"
};
inputRef = createRef();
displayWord = (word) => {
const Index = Math.floor(Math.random() * word.length);
let rword = word[Index];
this.setState({
current_word: rword
});
};
matchWords = (e) => {
this.setState({ current_input: e.target.value }, () => {
if (this.state.current_input === this.state.current_word) {
this.displayWord(this.state.words);
this.setState({
current_input: ""
});
this.inputRef.current.focus();
}
});
};
render() {
return (
<div>
<div>
<div>
<h2 id="current-word">{this.state.current_word}</h2>
<input
ref={this.inputRef}
value={this.state.current_input}
placeholder="start .."
onChange={(e) => this.matchWords(e)}
type="text"
id="word-input"
autoFocus
/>
</div>
</div>
</div>
);
}
}
Because of asynchronous operations current_input state update without last character.
Refer this: onChange in React doesn't capture the last character of text
Working demo of your code : https://codepen.io/navindu_d/pen/OJROmxN
Upvotes: 1
Reputation: 1862
I think, you should change your code inside function matchWords
like below:
matchWords = (e) => {
if (e.target.value === this.state.current_word) {
this.displayWord(this.state.words);
this.setState({
current_input: ""
});
this.inputRef.current.focus();
} else {
this.setState({
current_input: e.target.value
});
}
};
It does not run immediately as you expect because setState
runs asynchronously, when compare if (this.state.current_input === this.state.current_word)
the current input is the old value. Like when you type break
the comparison is if ('brea' === 'break')
Upvotes: 1