Last active
May 29, 2024 01:55
-
-
Save nfantone/9ab600760db8774ab4873cb1a3a22f26 to your computer and use it in GitHub Desktop.
Use `yup` with `react-final-form`
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { setIn } from 'final-form'; | |
import { useMemo } from 'react'; | |
/** | |
* Sets the `innerError.message` in an `errors` object at the key | |
* defined by `innerError.path`. | |
* @param {Object} errors The object to set the error in. | |
* @param {{ path: string, message: string }} innerError A `yup` field error. | |
* @returns {Object} The result of setting the new error message onto `errors`. | |
*/ | |
const setInError = (errors, innerError) => { | |
return setIn(errors, innerError.path, innerError.message); | |
}; | |
/** | |
* Empty object map with no prototype. Used as default | |
* value for reducing the `err.inner` array of errors | |
* from a `yup~ValidationError`. | |
* @type {Object} | |
*/ | |
const emptyObj = Object.create(null); | |
/** | |
* Takes a `yup` validation schema and returns a function that expects | |
* a map of values to validate. If the validation passes, the function resolves to `undefined` | |
* (signalling that the values are valid). If the validation doesn't pass, it resolves | |
* to a map of invalid field names to errors. | |
* @param {import('yup').ObjectSchema} schema `yup` schema definition. | |
* @returns {(values: Object) => Promise<?Object>} An async function that expects some `values` | |
* and resolves to either `undefined` or a map of field names to error messages. | |
*/ | |
export const makeValidate = schema => { | |
return async function validate(values) { | |
try { | |
await schema.validate(values, { abortEarly: false }); | |
} catch (err) { | |
return err.inner.reduce(setInError, emptyObj); | |
} | |
}; | |
}; | |
function useValidationSchema(schema) { | |
const validate = useMemo(() => makeValidate(schema), [schema]); | |
return validate; | |
} | |
export default useValidationSchema; |
const setInError = (errors: ValidationError, innerError: ValidationError): ValidationError =>
<ValidationError>setIn(errors, innerError.path ?? '', innerError.message);
const emptyObj: ValidationError = Object.create(null);
export const makeValidate = (schema: ObjectSchema<AnyObject>) => {
return async function validate(values: InferType<typeof schema>) {
try {
await schema.validate(values, { abortEarly: false });
} catch (errors: unknown) {
if (errors instanceof ValidationError) {
return errors.inner.reduce(setInError, emptyObj);
}
}
};
};
export const useValidationSchema = (schema: ObjectSchema<AnyObject>) => {
return useMemo(() => makeValidate(schema), [schema]);
};
TypeScript Users check out this gist.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Converted it to TS for anyone stumbling upon this: