Skip to content

Instantly share code, notes, and snippets.

@malerba118
Last active December 22, 2018 18:55
Show Gist options
  • Select an option

  • Save malerba118/92333ab2dc1c6264b98b104daec296cd to your computer and use it in GitHub Desktop.

Select an option

Save malerba118/92333ab2dc1c6264b98b104daec296cd to your computer and use it in GitHub Desktop.
export const useField = (
name,
form,
{ defaultValue, validations = [] } = {}
) => {
let [value, setValue] = useState(defaultValue);
let [errors, setErrors] = useState([]);
const validate = async () => {
let formData = form.getFormData();
let errorMessages = await Promise.all(
validations.map(validation => validation(formData, name))
);
errorMessages = errorMessages.filter(errorMsg => !!errorMsg);
setErrors(errorMessages);
let fieldValid = errorMessages.length === 0;
return fieldValid;
};
useEffect(
() => {
form.validateFields(); // Validate fields when value changes
},
[value]
);
let field = {
name,
value,
errors,
validate,
setErrors,
onChange: e => {
setValue(e.target.value);
}
};
// Register field with the form
form.addField(field);
return field;
};
export const useForm = ({ onSubmit }) => {
let fields = [];
const getFormData = () => {
// Get an object containing raw form data
return fields.reduce((formData, field) => {
formData[field.name] = field.value;
return formData;
}, {});
};
const validateFields = async () => {
let fieldsToValidate = fields;
let fieldsValid = await Promise.all(
fieldsToValidate.map(field => field.validate())
);
let formValid = fieldsValid.every(isValid => isValid === true);
return formValid;
};
return {
onSubmit: async e => {
e.preventDefault(); // Prevent default form submission
let formValid = await validateFields();
return onSubmit(getFormData(), formValid);
},
addField: field => fields.push(field),
getFormData,
validateFields
};
};
const Field = ({
label,
name,
value,
onChange,
errors,
setErrors,
validate,
...other
}) => {
let showErrors = !!errors.length;
return (
<FormControl className="field" error={showErrors}>
<InputLabel htmlFor={name}>{label}</InputLabel>
<Input
id={name}
value={value}
onChange={onChange}
onBlur={validate}
{...other}
/>
<FormHelperText component="div">
{showErrors &&
errors.map(errorMsg => <div key={errorMsg}>{errorMsg}</div>)}
</FormHelperText>
</FormControl>
);
};
const App = props => {
const form = useForm({
onSubmit: async formData => {
window.alert("Account created!");
}
});
const usernameField = useField("username", form, {
defaultValue: "",
validations: [
async formData => {
await timeout(2000);
return formData.username.length < 6 && "Username already exists";
}
]
});
const passwordField = useField("password", form, {
defaultValue: "",
validations: [
formData =>
formData.password.length < 6 && "Password must be at least 6 characters"
]
});
const confirmPasswordField = useField("confirmPassword", form, {
defaultValue: "",
validations: [
formData =>
formData.password !== formData.confirmPassword &&
"Passwords do not match"
]
});
return (
<div id="form-container">
<form onSubmit={form.onSubmit}>
<Field {...usernameField} label="Username" />
<Field {...passwordField} label="Password" type="password" />
<Field {...confirmPasswordField} label="Confirm Password" type="password" />
<Button type="submit">Submit</Button>
</form>
</div>
);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment