React方法中的多个setState()调用:如何使其“同步"工作? [英] Multiple setState() calls in a React method: How to make it work "synchronously"

查看:96
本文介绍了React方法中的多个setState()调用:如何使其“同步"工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我的React应用程序出现问题,我遇到了一种特殊情况,即我需要在一个方法中进行多个setState()调用,然后让代码运行 AFTER .下面的代码是一个对话框,用于在网站上添加帐户.

So I had a problem in my React application, I ran into a specific case where I needed to have multiple setState() calls in one method, and then have code run AFTER the states were set. The code below is a Dialog box used to add an account on the website.

import React from 'react';
import Dialog from 'material-ui/Dialog';
import FlatButton from 'material-ui/FlatButton';
import TextField from 'material-ui/TextField';

/**
 * A modal dialog can only be closed by selecting one of the actions.
 */
export default class NewAcctDia extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      userError: null,
      passError: null,
      passConfirmError: null,
    }

    this.handleOpen = this.handleOpen.bind(this);
    this.handleClose = this.handleClose.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleOpen() {
    this.setState({open: true});
  }

  handleClose() {
    this.setState({open: false});
  }

  handleSubmit() {
    if(!this.refs.user.getValue())
      this.setState({userError: "This field is required"});
    else
      this.setState({userError: null});

    if(!this.refs.pass.getValue())
      this.setState({passError: "This field is required"});
    else
      this.setState({passError: null});

    if(this.refs.pass.getValue() == this.refs.passConfirm.getValue()) {
      this.setState({passError: null});
    } else {
      this.setState({passConfirmError: "Passwords do not match"});
    }

    if(!this.state.userError && !this.state.passError && !this.state.passConfirmError)
      alert('worked');
  }

  render() {
    const actions = [
      <FlatButton
        label="Cancel"
        primary={true}
        onTouchTap={this.handleClose}
      />,
      <FlatButton
        label="Submit"
        primary={true}
        disabled={false}
        onTouchTap={this.handleSubmit}
      />,
    ];

    return (
        <Dialog
          title="Create an Account"
          actions={actions}
          modal={true}
          open={this.state.open}
          contentStyle={{width: 350}}
        >
          <TextField
            ref='user'
            floatingLabelText="Username"
            errorText={this.state.userError}
          /><br />
          <TextField
            ref='pass'
            floatingLabelText="Password"
            type="password"
            errorText={this.state.passError}
          /><br />
          <TextField
            ref='passConfirm'
            floatingLabelText="Confirm Password"
            type="password"
            errorText={this.state.passConfirmError}
          /><br />
        </Dialog>
    );
  }
}

问题出在handleSubmit()方法中,我需要检查用户是否在用户名和密码字段中输入了某些内容,以及密码和确认密码字段是否匹配.如果没有,我将错误文本添加到需要通过状态更改的字段中.然后,我尝试查看状态以查看是否存在任何错误.

The problem is in the handleSubmit() method, I needed to check to see that the user had entered something into the username and password fields, and that the passwords and confirm password fields matched. If they didn't, I would add error text to the fields that needed alteration via state. I then tried to look at the state to see if there were any errors.

不幸的是,正如我很快弄清楚的那样,setState()函数是异步的,这意味着状态在我进行最终检查之前不会更改.我搜索并遍历了所有方法,以等待状态更改后再执行代码,但结果空了.我现在已经解决了这个问题,并认为我会将其放在Stack上,以便其他人可以从我想出的方法中受益.我还想知道我在做什么的利弊,或者可能更有效的建议.

Unfortunately, as I quickly figured out, the setState() function is asynchronous, meaning the state would not get changed before my final check. I googled and searched all over for a way to wait for state to change before executing code but came up empty. I've solved this problem now and figured I would put it up on Stack so others might benefit from the method I came up with. I would also like to know any pros and cons of what I am doing, or any suggestions that might work better.

当我在Google上搜索时,遇到了一种向setState()发送回调的方法,如下所示:setState(data, callback).起初我不认为这对我有用,因为我有多个setState()调用.但是,我意识到我可以将handleSubmit()方法转换为带有三元组的单个setState()调用.像这样:

When I googled around I came across a method to send a callback to setState() as shown: setState(data, callback). I did not think this would work for me at first, as I had multiple setState() calls. However, I realized I could convert the handleSubmit() method to a single setState() call with ternaries. Like so:

handleSubmit() {
    this.setState({
      userError: (
        this.refs.user.getValue() ? null : "This field is required"
      ),
      passError: (
        this.refs.pass.getValue() ? null : "This field is required"
      ),
      passConfirmError: (
        (this.refs.pass.getValue() == this.refs.passConfirm.getValue()) ? 
          null : "Passwords do not match"
      )
    }, () => {
      if(!this.state.userError && !this.state.passError && !this.state.passConfirmError)
        alert('worked');
    })
}

状态更改后将执行匿名回调函数,从而使我的检查工作正常.

The anonymous callback function will be executed after the state is changed, allowing my check to work.

我预见到,使用此方法的唯一问题是嵌套的三元组,因为如果需要,它们可能会变得非常混乱.这可能会对我的程序产生不利影响吗?还是我可以解决这个问题的更好方法?

The only problems I foresee with this method are nested ternaries, as that may become extremely messy if they are required. Is there any adverse effects this might have on my program? Or better ways I could have solved this?

我希望我对某些人的解决方案有所帮助. :D

I hope I've helped some people with my solution. :D

推荐答案

反应

React documentation encourages the use of componentDidUpdate instead of the callback parameter of setState.

但是,如果您认为代码看起来有些混乱,请尝试使用本地const并单次调用setState:

Yet, if you think the code seems a bit messy, try out local consts and make a single call to setState:

handleSubmit() {
  const {user, pass, passConfirm} = this.refs;
  const userError = user.getValue() ? null : "This field is required";
  const passError = pass.getValue() ? null : "This field is required";
  const passConfirmError = !passError && pass.getValue() === passConfirm.getValue()
    ? null
    : "Passwords do not match";

  this.setState({userError, passError, passConfirmError});

  if(!userError && !emptyPassError && !passConfirmError)
    alert('worked');
}

最后,文档也建议使用字符串引用上的回调引用的数量:

Finally, documentation also recommends the use of callback refs over strings refs:

仅使用ref回调在类上设置属性是常见的 访问DOM元素的模式.如果您当前正在使用 this.refs.myRefName来访问引用,我们建议使用此模式 代替.

Using the ref callback just to set a property on the class is a common pattern for accessing DOM elements. If you are currently using this.refs.myRefName to access refs, we recommend using this pattern instead.

这篇关于React方法中的多个setState()调用:如何使其“同步"工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆