Skip to content

Instantly share code, notes, and snippets.

@pixeldrew
Created September 1, 2019 03:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pixeldrew/a1cccb125c9680e5424fd9fdee82ac88 to your computer and use it in GitHub Desktop.
Save pixeldrew/a1cccb125c9680e5424fd9fdee82ac88 to your computer and use it in GitHub Desktop.
Simple Form Hook
function useForm(callback, defaultValues, schema) {
const [values, setValues] = useState({ ...defaultValues });
const [errors, setErrors] = useState([]);
const [validateOnChange, setValidateOnChange] = useState(false);
async function validate() {
if (schema) {
const errors = await catchErrors();
if (errors.length > 0) {
setErrors([...errors]);
return false;
}
setErrors([]);
}
return true;
}
async function catchErrors() {
let caughtErrors = [];
for (let [id] of Object.entries(values)) {
try {
await schema.validateAt(id, values);
} catch ({ errors }) {
caughtErrors.push({
id,
msgs: errors[0]
});
}
}
return caughtErrors;
}
async function handleSubmit(event) {
if (event) event.preventDefault();
if (schema) {
setValidateOnChange(true);
if (await validate()) {
callback(values);
}
} else {
callback(values);
}
}
function handleChange(name) {
if (name.target) {
name.persist();
const key = name.target.name || name.target.id;
if (!key) {
throw new Error(
"no name provided to handleChange. input must have either a name or an id"
);
}
setValues(values => ({
...values,
[key]: name.target.value
}));
} else {
return event => {
event.persist();
setValues(values => ({
...values,
[name]: event.target.value
}));
};
}
}
useEffect(() => {
validateOnChange && validate();
}, [values]);
return {
handleChange,
handleSubmit,
values,
errors,
hasError: id => errors.findIndex(e => e.id === id) >= 0
};
}
export default useForm;
@pixeldrew
Copy link
Author

Example Usage:

import React from "react";
import { object, string } from "yup";

function UserForm({ submitForm }) {
  const { values, handleChange, handleSubmit, errors, hasError } = useForm(
    submitForm,
    {
      name: "",
      email: ""
    },
    object({
      name: string().required("Name is Required"),
      email: string().required("Email is Required")
    })
  );

  return (
    <form noValidate autoComplete="off" onSubmit={handleSubmit}>
      <input
        name="name"
        value={values.name}
        id="name"
        onChange={handleChange}
      />
      {hasError("name") && <p>errors: {errors.find(e => e.id === "name")}</p>}
      <input
        name="email"
        value={values.email}
        id="email"
        onChange={handleChange}
      />
      {hasError("email") && <p>errors: {errors.find(e => e.id === "email")}</p>}
      <input type="submit" value="submit" />
    </form>
  );
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment