Formulários simples eu costumo lidar apenas com uma referência, por exemplo:
const valueRef = useRef('');
function handleChange(e) {
valueRef.current = e.target.value;
}
function handleSubmit() {
callApi({ value: valueRef.current });
}
Isso evita rerenderizações desnecessárias causadas pelo useState
.
Para formulários maiores eu gosto de usar o useForm
do react-hook-form. Um exemplo da documentação deles:
import { useForm } from 'react-hook-form';
function App() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm();
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<input {...register('firstName')} />
<input {...register('lastName', { required: true })} />
{errors.lastName && <p>Last name is required.</p>}
<input {...register('age', { pattern: /\d+/ })} />
{errors.age && <p>Please enter number for age.</p>}
<input type="submit" />
</form>
);
}
Funciona bem. Com TypeScript você pode acabar sofrendo um pouco ao usar um componente controlado, mas eu acho que faz parte da complexidade, e não me arrependo de usar essa biblioteca. Conheci ela em 2020 ou 2021, antes usava o formik.