I have an App component which holds an input. Every time I type in the input, the value of the input updates and a Message component prints a different message, depending on how long the input is. At the same time, a third component called Character print to the screen every letter of the string, individually. The desired behavior is that when I click on one of the letters, it gets removed from the string, the new string is displayed on the screen and the input also gets updated with the new string.
I used some console.logs to debug and everything seems to be happening as expected, until the last step when I am trying to update the state, but for some reason, it doesn't get updated.
class App extends React.Component {
constructor(props) {
super(props);
this.state = { text: "" };
}
render() {
const handleUpdateText = event => {
this.setState({
text: event.target.value
});
};
const inputLength = this.state.text.length;
const toArray = this.state.text.split("");
const handleDeleteLetter = index => {
toArray.splice(index, 1);
console.log(toArray);
const updatedArray = toArray.join("");
console.log(updatedArray);
this.setState({ text: updatedArray });
console.log(this.state.text);
};
return (
<>
<input type="text" onChange={handleUpdateText} />
<Message inputLength={inputLength} />
{toArray.map((letter, index) => (
<Character
key={index}
theLetter={letter}
deleteLetter={() => handleDeleteLetter(index)}
/>
))}
</>
);
}
}
class Message extends React.Component {
render() {
const { inputLength } = this.props;
let codeToPrint = "The text is long enough!";
if (inputLength <= 5) {
codeToPrint = "The text is not long enough!";
}
return <p>{codeToPrint}</p>;
}
}
class Character extends React.Component {
render() {
const { theLetter, deleteLetter } = this.props;
return (
<div
style={{
display: "inline-block",
padding: "16px",
textAlign: "center",
margin: "16px",
backgroundColor: "tomato"
}}
onClick={deleteLetter}
>
{theLetter}
</div>
);
}
}
The complete code is here:
I don't really understand what am I doing wrong and I have a feeling is somehow related to a life cycle method. Any answer could help. Thank you.
State is getting updated, you just need to pass value
prop to the input so that input's value can be in sync with your state
<input type="text" value={this.state.text} onChange={handleUpdateText} />
And you're not seeing updated state just after setting it because setState
is asynchronous. That's why the console
statement just after the setState
statement shows the previous value.
Also you should move functions out of your render method, because everytime your component re-renders, new functions would be created. You can declare them as class properties and pass their reference
handleUpdateText = event => {
this.setState({
text: event.target.value
});
};
render() {
.......
return (
<>
<input type="text" onChange={this.handleUpdateText} />