【问题标题】:Does React discard queued events on state change?React 是否会在状态更改时丢弃排队的事件?
【发布时间】:2016-04-09 08:43:07
【问题描述】:

我正在制作一个带有简单验证的 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,它应该可以让您自己查看错误。任何帮助都将不胜感激。

【问题讨论】:

    标签: javascript reactjs forms validation dom-events


    【解决方案1】:

    感谢 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 }) 
        }
    }
    

    【讨论】:

      【解决方案2】:

      是的,更改组件中的状态会清除所有排队的事件,因为状态更改会导致整个组件重新渲染,并且事件将被清除并重新-附上

      我会在提交事件回调中进行验证,而不是模糊一个。如果您想在用户输入时进行验证,可以使用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/

      【讨论】:

      • 嗯,我很高兴是这样,而且不仅仅是我疯了。关于您的建议,部分要求是对模糊进行验证,因为 onKeyUp 或 onChange 会过早地显示电子邮件字段的错误消息。此外,表单中有 8 个字段,因此仅在提交时进行验证并不是特别用户友好。
      • 但是,验证失败时不需要提交表单,如果提交表单时状态在blur上没有改变,就会提交表单(提交事件回调将是执行)。
      • 确实如此。当字段的错误消息显示,用户更正它然后单击提交时,就会出现此问题。在这种情况下,表单应该提交,因为表单是有效的,但它没有提交,因为 onBlur 中的状态更改正在取消 onSubmit 事件。
      • 很遗憾,我也无法执行您的最新建议。表单仅应在单击提交按钮本身时提交。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-18
      • 2021-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-25
      相关资源
      最近更新 更多