Last active
December 22, 2018 18:55
-
-
Save malerba118/92333ab2dc1c6264b98b104daec296cd to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| 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