Skip to content

Instantly share code, notes, and snippets.

@arnonate
Created June 16, 2021 14:02
Show Gist options
  • Save arnonate/731b946dc157ff06ee4180705335da44 to your computer and use it in GitHub Desktop.
Save arnonate/731b946dc157ff06ee4180705335da44 to your computer and use it in GitHub Desktop.
import { useEffect, useState, FormEvent } from 'react';
type FormField = {
field: string;
errorMessage?: string;
hasError?: boolean;
required?: boolean;
value?: boolean | string | string[] | null;
};
export type FormFields = {
[key: string]: FormField;
};
export type UseForm = {
formState: FormFields;
getSubmitterShouldValidate: (event: FormEvent) => boolean;
getData: <T>() => T | null;
setData: (field: string, value: FormField['value']) => void;
getErrors: () => FormField[];
setErrors: (field: string, value: boolean) => void;
setRequired: (field: string, required: boolean) => void;
isDirty: boolean;
cleanForm: () => void;
};
const useForm = (initialState: Readonly<FormFields>): UseForm => {
const [cleanState, setCleanState] = useState<FormFields>({ ...initialState });
const [formState, setFormState] = useState<FormFields>({ ...initialState });
const [isDirty, setIsDirty] = useState<boolean>(false);
const getSubmitterShouldValidate = (event: FormEvent): boolean => {
const nativeEvent = (event.nativeEvent as unknown) as {
submitter: { formNoValidate: boolean };
};
return !nativeEvent.submitter.formNoValidate;
};
const getData = <T,>(): T | null => {
const postData = Object.values(formState);
const postBody = {};
if (postData.length < 1) {
return null;
}
return postData.reduce(
(obj, item) => ({
...obj,
[item.field]: item.value,
}),
postBody,
) as T;
};
const setData: UseForm['setData'] = (field, value) => {
setFormState((data) => ({
...data,
[field]: {
...data[field],
value,
hasError: false,
},
}));
};
const getErrors: UseForm['getErrors'] = () => {
const fields = Object.values(formState);
return fields.filter((field) => field.required && !field.value);
};
const setErrors: UseForm['setErrors'] = (field, value) => {
setFormState((data) => ({
...data,
[field]: {
...data[field],
hasError: value,
},
}));
};
const setRequired: UseForm['setRequired'] = (field, required) => {
setFormState((data) => ({
...data,
[field]: {
...data[field],
required,
},
}));
};
const cleanForm: UseForm['cleanForm'] = () => {
setCleanState({ ...formState });
};
useEffect(() => {
if (
JSON.stringify(Object.values(cleanState).map((item) => item.value)) ===
JSON.stringify(Object.values(formState).map((item) => item.value))
) {
setIsDirty(false);
} else {
setIsDirty(true);
}
}, [cleanState, formState]);
return {
formState,
getSubmitterShouldValidate,
getData,
setData,
getErrors,
setErrors,
setRequired,
isDirty,
cleanForm,
};
};
export default useForm;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment