import { useState, useEffect } from 'react'; export function WithForm(validators) { return function(Component) { return function WithFormWrapper({ errors, ...props }) { const [ formData, setFormData ] = useState({}); const [ formErrors, setFormErrors ] = useState(errors || {}); const [ submitted, setSubmitted ] = useState(false); const validateField = (name) => { if (typeof validators[name] !== 'function') return; const value = formData[name]; const result = validators[name](value, formData); setFormErrors(formErrors => { return { ...formErrors, [name]: result }; }); } useEffect(() => { Object.keys(formData).forEach(validateField); }, [formData]); useEffect(() => { setSubmitted(false); }, [submitted]); useEffect(() => { setFormErrors(errors || {}); }, [errors]); const form = { field: (name, defaultValue) => { return name in formData ? formData[name] : defaultValue; }, onChange: (name) => { return (evt) => { const value = evt.target.value; setFormData(formData => { return { ...formData, [name]: value }; }); }; }, hasError: (name) => { return name in formErrors ? formErrors[name].hasError : false; }, error: (name) => { return name in formErrors ? formErrors[name].message : ''; }, onSubmit: (evt) => { evt.preventDefault(); Object.keys(validators).forEach(validateField); setSubmitted(true); }, valid: !Object.values(formErrors).reduce((hasErrors, fieldError) => { return hasErrors || fieldError.hasError; }, false), data: { ...formData }, errors: { ...formErrors }, submitted, }; return ; }; } } // connect(mapStateToProps)(MyComponent)