I am trying to build a component that automatically checks an input field for a valid email address, then adds it to an array using setState
.
I have that part working correctly, but I also want it to remove the last item when you backspace on the empty field.
The problem I am having is that when I splice the last item in the array, and update it using setState
, it doesnt render the new array value?
If I log the value in the function called by onKeyDown
, it logs the correct updated array value of this.state.emails
. The render function however logs the old value and the list doesnt update.
Codepen: https://codepen.io/adamcoulombe/pen/zJxoER
class MultiEmailInput extends React.Component {
constructor(props) {
super(props)
this.state = {
emails:[]
};
}
fieldChange(e){
if (e.target.value !== ''){
if (this.validateEmail(e.target.value)===true){
this.setState({emails: this.state.emails.concat(e.target.value)});
}
}
}
fieldKeyDown(e){
// console.log(e.target.value);
if(e.target.value===''){
var key = e.keyCode || e.charCode;
if (key == 8 || key == 46) {
this.setState({ emails: this.state.emails.splice(-1) });
//logs correct updated value
console.log(this.state.emails);
}
}
}
validateEmail(email) {
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
render() {
//this value doesnt get updated?
console.log(this.state.emails);
return (
<div className={"email-multi-input"+this.props.className}>
<ul className="added-emails" ref="email-multi-input-added-emails">
{
this.state.emails.map((email, i) => {
return (<li key={i}>{email}</li>)
})}
</ul>
<input ref="email-multi-input-field" onChange={this.fieldChange.bind(this)} onKeyDown={this.fieldKeyDown.bind(this)} />
</div>
);
}
}
React.render(
<MultiEmailInput />,
document.body
);
The problem is with this line in fieldKeyDown
:
this.setState({ emails: this.state.emails.splice(-1) });
the splice
method mutates the array this.state.emails
and removes the last element, however it returns that last element. So that line above sets this.state.emails
equal to the last element of this.state.emails
.
The reason you see the correct value when you call console.log(this.state.emails)
in fieldKeyDown
is because the effect of this.setState
has not taken place yet since React does not update state immediately (See State Updates May Be Asynchronous ). So you are looking at the old this.state.emails
, which has been mutated. When you console.log
in render
you see the new value because render
is called after state has been updated.
An additional note: You should not mutate state directly (ie using splice
) instead you should only change state using setState
. For this problem you can set this.state.emails
equal to a slice
of this.state.emails
. Here's an example:
this.setState({ emails: this.state.emails.slice(0, -1) });
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.