0

所以我在我的 React 应用程序中遇到了一个问题,我遇到了一个特定的情况,我需要setState()在一个方法中进行多次调用,然后在设置状态让代码运行。下面的代码是一个用于在网站上添加帐户的对话框。

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()方法上,我需要检查用户是否在用户名和密码字段中输入了某些内容,并且密码和确认密码字段是否匹配。如果他们没有,我会在需要通过状态更改的字段中添加错误文本。然后我尝试查看状态以查看是否有任何错误。

不幸的是,正如我很快发现的那样,该setState()函数是异步的,这意味着在我最终检查之前状态不会改变。我在谷歌上搜索并搜索了一种在执行代码之前等待状态改变的方法,但结果是空的。我现在已经解决了这个问题,并认为我会把它放在 Stack 上,这样其他人可能会从我提出的方法中受益。我还想知道我正在做的任何利弊,或者任何可能会更好的建议。

当我四处搜索时,我发现了一种发送回调的方法,setState()如图所示:setState(data, callback). 起初我不认为这对我有用,因为我有多个setState()电话。但是,我意识到我可以将该handleSubmit()方法转换为使用三元组的单个setState()调用。像这样:

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');
    })
}

匿名回调函数将在状态更改后执行,让我的检查工作。

我预见到这种方法的唯一问题是嵌套三元组,因为如果需要它们可能会变得非常混乱。这可能对我的程序有任何不利影响吗?或者我可以解决这个问题的更好方法?

我希望我的解决方案帮助了一些人。:D

4

1 回答 1

2

React文档鼓励使用componentDidUpdate代替 的回调参数setState

但是,如果您认为代码看起来有些混乱,请尝试使用本地 const 并调用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');
}

最后,文档还建议在字符串 refs 上使用回调 refs:

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

于 2016-12-07T03:03:39.550 回答