73 lines
2.3 KiB
JavaScript
73 lines
2.3 KiB
JavaScript
|
import { useState, useEffect } from 'react';
|
||
|
|
||
|
export function WithForm(validators) {
|
||
|
|
||
|
return function(Component) {
|
||
|
|
||
|
return function WithFormWrapper(props) {
|
||
|
|
||
|
const [ formData, setFormData ] = useState({});
|
||
|
const [ formErrors, setFormErrors ] = useState({});
|
||
|
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]);
|
||
|
|
||
|
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 <Component form={form} {...props} />;
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// connect(mapStateToProps)(MyComponent)
|