首页 > 解决方案 > 使用 this.setState 后反应不以正确的状态值呈现

问题描述

我正在尝试构建一个组件,该组件会自动检查输入字段中的有效电子邮件地址,然后使用setState.

我的那部分工作正常,但我也希望它在您在空白字段上退格时删除最后一项。

我遇到的问题是,当我拼接数组中的最后一项并使用 更新它时setState,它不会呈现新的数组值吗?

如果我将值记录在由 调用的函数中onKeyDown,它会记录正确更新的数组值this.state.emails。但是,渲染函数会记录旧值并且列表不会更新。

代码笔: 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
);

标签: javascriptreactjs

解决方案


问题在于这一行fieldKeyDown

this.setState({ emails: this.state.emails.splice(-1) });

splice 方法改变数组this.state.emails并删除最后一个元素,但是它返回最后一个元素。所以上面的那一行this.state.emails等于 的最后一个元素this.state.emails

console.log(this.state.emails)调用时看到正确值的原因是,由于 React 不会立即更新状态(请参阅状态更新可能是异步的) ,因此尚未发生fieldKeyDown效果。因此,您正在查看已变异的 old 。当您进入时,您会看到新值,因为在状态更新后调用。this.setStatethis.state.emailsconsole.logrenderrender

附加说明:您不应直接更改状态(即使用splice),而应仅使用更改状态setState。对于这个问题,您可以设置this.state.emails等于 a sliceof this.state.emails。这是一个例子:

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

推荐阅读