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.

Nesse caso de um formulário tão simples, o custo do useRef não acaba sendo maior do que um rerender causado pelo useState?

Essa é uma dúvida recorrente que tenho, o que é menos custoso em termos de processamento?

O custo do `useState` na verdade depende do tanto de coisa que está sendo rerenderizado. Na maior parte das vezes, você nem vai perceber diferença, é só um detalhe de otimização e o desenvolvedor acaba optando o caminho que está acostumado. Se estiver com o desempenho ruim, então você acaba procurando alternativas, usar menos estado, ou componentes menores, vendo o que é possível melhorar. O `useRef` na verdade não me parece ter um custo envolvido que possamos usar para comparação com o `useState`. Lendo a [documentação](https://react.dev/reference/react/useRef), a parte mais relevante que encontrei foi: > When you change the `ref.current` property, React does not re-render your component. React is not aware of when you change it because a ref is a plain JavaScript object. Ou seja, é só um objeto JavaScript onde você muda o valor do atributo `current`.

até hoje eu não consigo usar useForm, yup, zod, joi direito kkk mas tambem eu até hoje não parei pra aprender, então fico quebrando a cabeça. Onde eu trabalho o carro chefe é um app que gera diversos tipos de formulários dinâmicos, cada um com várias particularidades e situações adversas que eu não sei como aplicar essas coisas usando essas ferramentas