React 方法中的多个 setState() 调用:如何使其工作 "synchronously"
Multiple setState() calls in a React method: How to make it work "synchronously"
所以我在我的 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
Reactdocumentation鼓励使用componentDidUpdate
代替setState
的回调参数。
但是,如果您认为代码看起来有点混乱,请尝试使用局部常量并调用 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');
}
最后,documentation 还建议在字符串引用上使用回调引用:
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()
调用,然后有代码 运行 在 之后设置状态。下面的代码是一个用于在网站上添加帐户的对话框。
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
Reactdocumentation鼓励使用componentDidUpdate
代替setState
的回调参数。
但是,如果您认为代码看起来有点混乱,请尝试使用局部常量并调用 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');
}
最后,documentation 还建议在字符串引用上使用回调引用:
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.