Open revskill10 opened 5 years ago
What API do you imagine for that?
@streamich I'm not sure about validation part, but for form, the api should be simple, based on standard html input types.
const { useCheckbox, useText, useImage, useRadio, useButton, useFile,
useHidden, usePassword, useReset, useSubmit, useButton } = useForm()
const { value, setValue } = useCheckbox(defaultValue)
...
Maybe something like this:
const {useForm, useText, usePassword} = formHooks('my-form');
const Demo = () => {
const state = useForm();
const inputEmail = useText('email', 'Enter your e-mail');
const inputPassword = usePassword('password', 'Password...');
const onSubmit = useCallback(() => {
// ...
});
return (
<form onSubmit={onSubmit}>
<input {...inputEmail} />
<input {...inputPassword} />
<button type="submit">Submit</button>
</form>
);
};
I don't know, it looks like there is a lot to think about.
@streamich I'm testing this code:
import { useState } from 'react'
import Validator from 'fastest-validator'
export const useForm = (initialState, schema) => {
const [values, setValues] = useState(initialState)
const [errors, setErrors] = useState({})
const v = new Validator();
const check = v.compile(schema);
const updateValues = (value, name) => {
setValues({ ...values, [name]: value})
}
const onChange = (value, name) => {
if (value.target) {
const e = value
updateValues(e.target.name, e.target.value)
} else {
updateValues(name, value)
}
}
const onSubmit = (e) => {
e.preventDefault()
const errors = check(values)
if (errors.length > 0) {
setErrors(errors)
} else {
setErrors([])
}
}
return {
values,
errors,
onChange,
onSubmit,
}
}
export default useForm
Usage like this
import { useForm } from 'lib/hooks/form'
const initialState = {
firstName: "Truong",
lastName: "Dung",
age: 30,
}
const schema = {
firstName: { type: "string" },
lastName: { type: "string", optional: true },
age: { type: "number", optional: true },
}
const TestForm = () => {
const {
values,
errors,
onChange,
onSubmit,
} = useForm(initialState, schema)
return (
<div>
<h1>New User</h1>
<div>{JSON.stringify(errors)}</div>
<form onSubmit={onSubmit} >
<label>First name</label>
<input type="text" name="firstName" onChange={onChange} value={values.firstName} />
<label>Last name</label>
<input type="text" name="lastName" onChange={onChange} value={values.lastName} />
<label>Age</label>
<input type="text" name="age" onChange={onChange} value={values.age} />
<button type="submit">Submit</button>
</form>
</div>
)
}
export default TestForm
There's an error that prevent field to change its value.
Formik will have form hooks, I think no need here
Here is a nice simple interface:
@streamich @revskill10 I prefer this API, which provides all the validation functionalities and uses validator
under the hood.
const [
{ emai: { value, errorText, isValid } },
handleFieldChange,
handleFieldBlur,
handleFieldFocus,
validateFieldAfterSubmit,
] = useForm({
email: {
value: '',
validationRules: [
{
method: isEmpty,
validWhen: false,
errorText: 'This field should not be left empty!',
},
{
method: isEmail,
errorText: 'This field should contain an email!',
},
],
},
});
Then just plug all the returned functions into an input
<input onChange={handleFieldChange} onFocus={handleFieldFocus} onBlur={handleFieldBlur} value={value} />
I've implemented this hook naively (source code) and the demo of the hook can be found at the bottom of my portfolio: https://brian-le.surge.sh.
I could rewrite this hook for better performance and readability and open a PR if required :)
Edit: validateFieldAfterSubmit
is used to validate each field one by one after submit, for example:
const handleSubmit = useCallback(
async e => {
e.preventDefault();
if (!validateFieldAfterSubmit('email')) return;
try {
// async code here
} catch (err) {
setFormMsg('Oops, something went wrong');
return;
}
setFormMsg('Success!');
},
[validateFieldAfterSubmit],
);
Any idea on useForm with (async) validation as a hook ?