简体   繁体   English

使用this.setState后反应不渲染具有正确的状态值

[英]React not rendering with correct state value after using this.setState

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 . 我正在尝试构建一个组件,该组件将自动检查输入字段中的有效电子邮件地址,然后使用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? 我遇到的问题是,当我拼接数组中的最后一项,并使用setState更新它时,它不会呈现新的数组值吗?

If I log the value in the function called by onKeyDown , it logs the correct updated array value of this.state.emails . 如果将值记录在onKeyDown调用的函数中,它将记录this.state.emails的正确更新数组值。 The render function however logs the old value and the list doesnt update. 但是,渲染功能会记录旧值,并且列表不会更新。

Codepen: https://codepen.io/adamcoulombe/pen/zJxoER 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 : 问题出在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. splice方法this.state.emails数组并删除了最后一个元素,但是它返回了最后一个元素。 So that line above sets this.state.emails equal to the last element of this.state.emails . 因此,上述套该行this.state.emails等于最后一个元素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 ). fieldKeyDown调用console.log(this.state.emails)时看到正确值的原因是,由于React不会立即更新状态,因此this.setState的影响尚未发生(请参阅状态更新可能是异步的 ) 。 So you are looking at the old this.state.emails , which has been mutated. 因此,您正在查看已this.state.emails的旧this.state.emails When you console.log in render you see the new value because render is called after state has been updated. 当您在render console.log ,您会看到新值,因为在状态更新后调用了render

An additional note: You should not mutate state directly (ie using splice ) instead you should only change state using setState . 补充说明:您不应直接更改状态(即使用splice ),而应仅使用setState更改状态。 For this problem you can set this.state.emails equal to a slice of this.state.emails . 对于这个问题,你可以设置this.state.emails等于slicethis.state.emails Here's an example: 这是一个例子:

this.setState({ emails: this.state.emails.slice(0, -1) });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM