formik
formik copied to clipboard
setValue cancels setError
Bug report
I would like to integrate formik and react-dropzone. in this library we have a onDrop
callback with acceptedFiles
and fileRejections
properties. So it make sense to call both helpers.setValue(acceptedFiles)
and helpers.setError
when we select multiple valid and invalid files
Current Behavior
unfortunately setValue
cancels setError
regardless of the order of call
Expected behavior
setValue
and setError
should be independent
Reproducible example
https://codesandbox.io/s/inspiring-gianmarco-tytzq7?file=/src/App.tsx
Please comment helpers.setValue('Value')
and see the result as well
Suggested solution(s)
Additional context
Your environment
Software | Version(s) |
---|---|
Formik | 2.4.2 |
React | 18.2.0 |
TypeScript | Version 5.1.3 |
Browser | Chrome |
npm/Yarn | npm 9.6.7 |
Operating System | Windows |
I have same problem, not only with setFieldValue
also with setFieldTouched
.
They are undo changes of setErrors
I guess They have set the error value respective with the fieldValue. If fieldValue changes then all the error will be gone. Looks like normal behavior to me
edit: the below works because setFieldError/Value are async calls : currently i am doing this:
useEffect(() => {
const errors = {};
/**
* toVerifyList is an object with sub objects containing a regex and err message to test the values
* const toVerifyList: {
* [x: string]: {
* regEx: string;
* errMsg: string;
* };
* }
*/
Object.keys(toVerifyList).forEach((item) => {
const fieldValidation = toVerifyList[item];
const fieldValue = values[item];
if (fieldValue && !RegExp(fieldValidation.regEx).test(fieldValue.toString())) {
errors[item] = fieldValidation.errMsg;
}
});
// Update validation errors
setValidationErrors(errors);
}, [isValidating, values]);
// Set error messages and touched state based on validationErrors
useEffect(() => {
Object.keys(validationErrors).forEach((item) => {
setFieldTouched(item, true, false);
setFieldError(item, validationErrors[item]);
});
}, [validationErrors, setFieldError, setFieldTouched]);
previously, I was handling this is using a setTimeout
setTimeout(() => {
setFieldTouched('item', true, false);
setFieldError('item', 'errMsg');
}, 100);
but both ways are bad ideas, as it causes the errors to be cleared an re-instated, causing layout shifts, which i handled with more UI stuff but this works