React在状态更改时丢弃排队的事件

Does React discard queued events on state change?

本文关键字:排队 事件 状态 React      更新时间:2024-03-18

我正在制作一个带有简单验证的React表单组件。每个字段都在模糊上进行验证,并且表单具有一个简单的onSubmit函数。布尔值存储在字段是否应显示错误消息的状态中,并在验证期间更新。

除了同时触发字段的onBlur和表单的`onSubmit之外,其他一切都很好。即,我在字段中键入一些内容,然后立即单击提交按钮。

首先执行onBlur,如果验证状态没有变化,则按预期执行onSubmit。但是,如果onBlur更改状态,则onSubmit函数永远不会被调用

所以我的问题是;在组件中设置状态是否会清除任何排队的事件?对此问题有任何可能的解决方案吗?

这是我代码的简化版本:

class SimpleForm extends React.Component {
    constructor(props) {
        super(props);
        this.handleBlur = this.handleBlur.bind(this);
        this.state = { shouldShowError: false }
    }
    handleBlur(event) {
        console.log("blur")
        const isEmpty = event.target.value === ""
        this.setState({ shouldShowError: isEmpty })
    }
    handleSubmit(event) {
        event.preventDefault()
        console.log("submit")
    }
    render() {
        return ( 
            < form onSubmit = { this.handleSubmit} >
                < input type = "text" onBlur = { this.handleBlur } /> 
                { this.state.shouldShowError ? < p > This field is required. < /p> : null } 
                < button type = "submit" > Submit < /button > 
            < /form>
        )
    }
};
ReactDOM.render(< SimpleForm / >, document.getElementById('container'));

还有一个JSFiddle,它应该让你自己看到错误。任何帮助我们都将不胜感激。

感谢Manolo证实了我的怀疑,即是状态更改擦除了事件队列。我想我已经找到了一个解决方案:

如果你同时需要onBlur和onSubmit主体来执行,你可以将onBlur主体包装在setTimeout中,这样它就会被放在任务队列中,并在onSubmit:之后执行

handleBlur(event) {
    const value = event.target.value
    setTimeout(() => {
        console.log("blur")
        const isEmpty = value === ""
        this.setState({ shouldShowError: isEmpty }) 
    }, 10)
}

请注意,在react中,默认情况下不能异步访问事件,因此需要提取超时之外所需的值,或者调用event.persist().

我不需要onBlur主体来执行,因为我的onSubmit也会验证表单。经过一点阅读,我发现你可以调用event.relatedTarget来访问焦点转移到的组件。所以我可以检查它是否是提交按钮,如果不是,只执行onBlur主体:

handleBlur(event) {
    if (!event.relatedTarget || event.relatedTarget.id !== 'submit') {
        console.log("blur")
        const isEmpty = event.target.value === ""
        this.setState({ shouldShowError: isEmpty }) 
    }
}

是的,更改组件中的状态会清除任何排队的事件,因为状态更改会导致整个组件被重新渲染,并且事件会被清除并重新附加。

我会在提交事件回调中进行验证,而不是模糊验证。若要在用户输入时进行验证,可以使用onKeyUp

如果你想保留你的示例行为,你可以在出现错误并且没有错误时在onBlur回调中提交表单:

class SimpleForm extends React.Component {
    constructor(props) {
        super(props);
        this.handleBlur = this.handleBlur.bind(this);
        this.state = { shouldShowError: false }
    }
    handleBlur(event) {
        console.log("blur")
        const isShowingError = this.state.shouldShowError;
        const isEmpty = event.target.value === ""
        if (isShowingError && !isEmpty) {
          console.log("submit the form");
        }
        this.setState({ shouldShowError: isEmpty })
    }
    handleSubmit(event) {
        event.preventDefault()
        console.log("submit")
    }
    render() {
        return ( 
          < form onSubmit = { this.handleSubmit} >
                < input type = "text" onBlur = { this.handleBlur } /> 
                { this.state.shouldShowError ? < p > This field is required. < /p> : null } 
                < button type = "submit" > Submit < /button > 
            < /form>
        )
    }
};
ReactDOM.render(< SimpleForm / >, document.getElementById('container'));

https://jsfiddle.net/2r9ua1n1/3/