Asynchronous `validate` prop of `FieldArray` put unresolved promise as `FINAL_FORM/array-error` instead of resolved value
usavkov-epam opened this issue · 1 comments
Are you submitting a bug report or a feature request?
bug report
What is the current behavior?
If we provide an asynchronous function as validate prop to FieldArray component to perform asynchronous validation of field array itself, then unresolved promise is set as FINAL_FORM/array-error for this field. This causes problems if we want to check the form for errors or display an error message because the promise, even if it resolves to "undefined", is in the form's errors object.
What is the expected behavior?
FieldArray's asynchronous validate function resolved with:
undefined(null) - field is valid, no errors set asFINAL_FORM/array-error- otherwise - resolved value set as
FINAL_FORM/array-error
StackBlitz Link
https://stackblitz.com/edit/react-ts-57t92d?file=App.tsx,components%2FRepeatableField.tsx
What's your environment?
{
"final-form": "^4.20.7",
"final-form-arrays": "^3.0.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-final-form": "^6.5.9",
"react-final-form-arrays": "^3.1.4",
}
Other information
Synchronous validation work as expected, but not async.
[edit]
Unfortunately the workaround (with useState) is not enough, the form sees the promise stored as an error and never state as valid so.
It seems that making the validator async in useFieldArray works:
cf.
react-final-form-arrays/src/useFieldArray.js
Lines 43 to 56 in a19c686
const validate: FieldValidator = useConstant(
// !!! First change, make validate a Promise
() => async (value, allValues, meta) => {
if (!validateProp) return undefined;
// !!! Second change, resolve eventual Promise before testing if it's a valid error or an array
const error = await Promise.resolve(validateProp(value, allValues, meta));
if (!error || Array.isArray(error)) {
return error;
}
const arrayError = [];
// gross, but we have to set a string key on the array
((arrayError: any): Object)[ARRAY_ERROR] = error;
return arrayError;
}
);[archive]:
Thanks for the workaround (cf. StackBlitz link above).
For the record:
// `meta` from FieldArray render prop
const { error } = meta;
const [resolvedError, setResolvedError] = React.useState();
React.useEffect(() => {
Promise.resolve(error).then(setResolvedError);
}, [error]);