我正在处理有关出于验证目的而在React中更新状态的许多问题,无论如何,我总是在渲染或类似操作之后更新状态,无论如何,我看到很多人使用setState中的回调函数来解决此问题但对我来说,总是回来
"Warning: An update (setState, replaceState, or forceUpdate) was scheduled from inside an update function. Update functions should be pure, with zero side-effects. Consider using componentDidUpdate or a callback."
这是我的带回调函数的setState
state = {
index: 0,
activeInput: '',
errors: {
error: false,
errorNombre: false,
errorCuil: false,
errorEmail: false,
errorContrasena: false,
errorCalle: false,
errorNumero: false,
errorProvincia: false,
errorLocalidad: false
},
values: {...this.props.initialValues}
};
_onChangeValue = (name, value) => {
this.setState(prevState => {
return {
values: {
...prevState.values,
[name]: value
}
}, this.validate(name)
})
};
这是Validate Function,是一个开关,所以我花了更长的时间,但问题可能是每种情况下都有另一个setState ...
validate = input => {
switch(input){
case 'nombre':
let { nombre } = this.state.values
let splitNombre = nombre.split(' ');
if ( splitNombre.length > 1 && splitNombre[1].length === 0 || nombre.length === 0 || splitNombre.length === 1 ) {
this.setState(prevState => ({
errors: { ...prevState.errors, error: true, errorNombre: true }
}));
} else {
this.setState(prevState => ({
errors: { ...prevState.errors, error: false, errorNombre: false }
}));
}
break
这是一个复合组件,有点混乱,但是这里是文件
Input.js
import React, { PureComponent } from 'react';
class Input extends PureComponent {
_onChangeText = text => {
this.props.onChangeValue(this.props.name, text);
};
render() {
const { onChangeValue, name, ...rest } = this.props;
return (
<input {...rest} onChange={(event) => this._onChangeText(event.target.value)} />
);
}
}
export default Input;
Steps.js
import Botones from './Botones'
export default class Step extends PureComponent {
state = {}
render() {
return (
<Fragment>
{this.props.children({
onChangeValue: this.props.onChangeValue,
values: this.props.values,
index: this.props.index,
errors: this.props.errors
})}
<div>
<Botones currentIndex={this.props.currentIndex}
prevStep={this.props.prevStep}
nextStep={this.props.nextStep}
onSubmit={this.props.onSubmit}
isLast={this.props.isLast}
isFirst={this.props.isFirst}
error={this.props.errors.error}
/>
</div>
</Fragment>
)
}
}
FirstStep.js
import Steps from './Steps';
export default class FirstStep extends Component {
constructor(props){
super(props)
this.state = {}
}
render() {
//console.log(this.props)
return (
<Fragment>
<Steps level={this.props.index}/>
<form onSubmit={this.onSubmit} className="mt90">
<div>
<label>Nombre completo</label>
<input type="text"
name="nombre"
placeholder="Escriba su nombre"
onChange={ event => this.props.onChangeText('nombre', event.target.value) }
value={this.props.values.nombre}
className={ `${ this.props.errors.errorNombre && "error-focus" }` }
/>
{ this.props.errors.errorNombre &&
<span className="error">No es un nombre completo</span> }
</div>
<div className="mt50">
<label>N° de CUIL</label>
<input type="text"
name="cuil"
placeholder="Ej.: 23-45678901-2"
onChange={ event => this.props.onChangeText('cuil', event.target.value) }
value={this.props.values.cuil}
className={ `${ this.props.errors.errorCuil && "error-focus" }` }
/>
{ this.props.errors.errorCuil &&
<span className="error">No es un CUIL válido</span> }
</div>
</form>
</Fragment>
)
}
}
App.js(具有FirstStep作为子组件)
[...]
Render()
<RegisterBox.Step>
{ ({ values, onChangeValue, index, errors }) => (
<FirstStep values={values} onChangeText={onChangeValue} index={index} errors={errors} />
)}
</RegisterBox.Step>
[...]
注意:我试图在componentDidUpdate内部进行更新,但这会返回一个无限循环。
答案 0 :(得分:1)
好像您犯了一个小的印刷错误。您的解决方案应该看起来像这样。
_onChangeValue = (name, value) => {
this.setState(prevState => {
return {
values: {
...prevState.values,
[name]: value
}
}
}, () => this.validate(name));
};
请注意,对this.validate
的呼叫已移出一组括号。其次,它被包装在一个匿名函数中,因此它实际上可以用作回调。
我想这会导致一些令人困惑的行为。由于comma operator,您的setState不会对值进行任何更新,而是仅使用您的验证结果来更新状态!
答案 1 :(得分:0)
我认为您需要重新考虑这个问题。为了确保我们步调一致,让我重申几件事。
首先setState
是异步的,更像是React发出的更新状态对象并调用React生命周期函数的信号。
不建议嵌套setState
,因为很难推断出异步调用的行为。
您需要重组函数以避免嵌套setState
。在这个简短的答复中,我无法为您做到这一点,您最清楚自己想怎么做。您需要注意的一件事是,有时您可以序列化setState
调用,以确保在当前setState
调用中看到的prevState实际上来自上一个调用。一种有效的方法是用setState
包装Promise
并使用await/async
序列化调用。
希望这会有所帮助。