I am dealing with a lot of problems about updating states in React for validation purposes, and always my state update after the render or something like that, anyway, I saw that many people solve this using a callback function in the setState
, but it always throws the following warning.
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.
I tried to update inside componentDidUpdate
, but that results in an infinite loop.
This is my setState
with the callback function.
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)
})
};
And this is the Validate Function, is a switch, so i much longer but the problem maybe could be that every case has another setState inside...
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
As this is a compound component is a little messy but here is the files
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 (has the FirstStep as a child component)
[...]
Render()
<RegisterBox.Step>
{ ({ values, onChangeValue, index, errors }) => (
<FirstStep values={values} onChangeText={onChangeValue} index={index} errors={errors} />
)}
</RegisterBox.Step>
[...]
The componentDidUpdate event is triggered whenever there is a state or props update. ComponentDidUpdate() has access to three properties, two of which are most often used more than the third. These are prevProps, prevState and lastly, snapshot, which is used less often.
If you try to update state directly then it won't re-render the component.
To update state in React components, we'll use either the this. setState function or the updater function returned by the React. useState() Hook in class and function components, respectively.
setState , and React. useState create queues for React core to update the state object of a React component. So the process to update React state is asynchronous for performance reasons. That's why changes don't feel immediate.
Looks like you've made a small typographical error. Your solution should look a bit more like this.
_onChangeValue = (name, value) => {
this.setState(prevState => {
return {
values: {
...prevState.values,
[name]: value
}
}
}, () => this.validate(name));
};
Notice the call to this.validate
has moved out one set of brackets. Secondly, it's been wrapped in an anonymous function, so that it can actually be used as a callback.
I imagine this would have resulted in some confusing behaviour. Because of the comma operator, your setState would not have made any update to values, instead updating state with only the results of your validation!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With