Criando formulários de reação em 2020

Olá, Habr. Apresento a você a tradução do artigo "Criando formulários em reagir em 2020", de Kristofer Selbekk

imagem


Campos de entrada Áreas de texto. Botões de opção e caixas de seleção. Aqui estão alguns dos principais pontos de interação que nós, como desenvolvedores, temos com nossos usuários. Nós os colocamos no site, os usuários os preenchem e, se tivermos sorte, os formulários preenchidos chegam até nós sem erros de validação.

O processamento de formulários é parte integrante de um grande número de aplicativos da Web, e essa é uma das coisas que o React faz melhor. Você tem grande liberdade para criar e processar formulários. Mas existe uma maneira melhor de fazer isso?

Observe que em todos esses exemplos, criaremos um formulário de login com um campo de email e senha, mas esses métodos podem ser usados ​​com a maioria dos tipos de formulários.

Lembre-se das regras de boa forma


Embora isso não esteja diretamente relacionado ao tópico em discussão, quero garantir que você não tenha esquecido de tornar seus formulários compreensíveis para todos. Adicione tags aos seus campos de entrada, defina os atributos da ária correta para os casos em que a entrada é inválida e estruture seu conteúdo semanticamente corretamente. Isso facilita o uso do formulário para usuários e desenvolvedores.

Processando formulários usando o gancho de estado


Para começar, vamos ver como eu costumo trabalhar com o estado do formulário. Eu salvo todos os campos como elementos de estado separados e os atualizo todos separadamente, que se parece com isso:

function LoginForm() {
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(email, password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={email} onChange={(e) => setEmail(e.target.value)} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={password} onChange={(e) => setPassword(e.target.value)} />
      </div>
    </form>
  );
}

Primeiro, eu crio duas partes separadas do estado - nome de usuário e senha. Essas duas variáveis ​​são então transferidas para o campo de entrada correspondente, determinando o valor desse campo. Sempre que algo em um campo muda, temos a certeza de atualizar o valor do estado, causando um redesenho do nosso aplicativo.

Esse processamento de formulários funciona bem na maioria dos casos e é simples e fácil de usar e entender. No entanto, é bastante entediante escrever essa construção toda vez.

Criando um gancho personalizado


Vamos refatorar um pouco e criar nosso próprio gancho, o que melhorará um pouco nosso código:

const useFormField = (initialValue: string = '') => {
  const [value, setValue] = React.useState(initialValue);
  const onChange = React.useCallback((e: React.ChangeEvent<HTMLInputElement>) => setValue(e.target.value), []);
  return { value, onChange };
};

export function LoginForm() {
  const emailField = useFormField();
  const passwordField = useFormField();

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(emailField.value, passwordField.value);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' {...emailField} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' {...passwordField} />
      </div>
    </form>
  );
}

Criamos um gancho useFormField personalizado que cria um manipulador de eventos onChange para nós e também armazena o valor no estado do formulário. Nesse caso, podemos usar nosso gancho com todos os campos do formulário.

Processando um grande número de campos


A desvantagem dessa abordagem é que ela não é dimensionada bem à medida que seu formulário cresce. Para formulários pequenos como login, isso provavelmente é bom, mas quando você cria formulários de perfil de usuário, pode ser necessário solicitar muitas informações! Devemos chamar nosso gancho de novo e de novo?

Sempre que encontro uma situação semelhante, costumo escrever um gancho personalizado que armazena todas as minhas formas em um grande fragmento. Pode ser assim:

export function LoginForm() {
  const { formFields, createChangeHandler } = useFormFields({
    email: '',
    password: '',
  });

  const handleSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    api.login(formFields.email, formFields.password);
  };
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label htmlFor='email'>Email</label>
        <input type='email' id='email' value={formFields.email} onChange={createChangeHandler('email')} />
      </div>
      <div>
        <label htmlFor='password'>Password</label>
        <input type='password' id='password' value={formFields.password} onChange={createChangeHandler('password')} />
      </div>
    </form>
  );
}

Com o gancho useFormFields, podemos continuar adicionando campos sem adicionar complexidade ao nosso componente. Podemos acessar todos os estados do formulário em um só lugar, e nosso código parece limpo e conciso. Obviamente, você provavelmente precisará usar o setState para algumas situações, mas para a maioria dos formulários a técnica acima é adequada.

Abordagem alternativa


Portanto, a manipulação de estado funciona bem e, na maioria dos casos, é a abordagem preferida no React. Mas você sabia que existe outro caminho? Acontece que o navegador, por padrão, processa o estado interno do formulário, e podemos usá-lo para simplificar nosso código!

Aqui está o mesmo formulário, mas permitindo que o navegador manipule o estado do formulário:

export function LoginForm() {
  const handleSubmit = (e: React.FormEvent) => {
	e.preventDefault();
	const formData = new FormData(e.target as HTMLFormElement);
	api.login(formData.get('email'), formData.get('password'));
  };
  return (
	<form onSubmit={handleSubmit}>
  	<div>
    	<label htmlFor="email">Email</label>
    	<input
      	type="email"
      	id="email"
      	name="email"
    	/>
  	</div>
  	<div>
    	<label htmlFor="password">Password</label>
    	<input
      	type="password"
      	id="password"
      	name="password"
    	/>
  	</div>
  	<button>Log in</button>
	</form>
  );
}

Olha como é fácil! Não foi utilizado um único gancho, não há configuração de valor inicial, não há manipulador onChange. A melhor parte é que o código ainda funciona como antes - mas como?

Você deve ter notado que estamos fazendo algo um pouco diferente na função handleSubmit. Usamos a API interna do navegador chamada FormData. FormData é uma maneira conveniente (e bem suportada) de obter valores de nossos campos de entrada!

Obtemos um link para o formulário no DOM por meio do atributo target do evento submit e criamos uma nova instância da classe FormData. Agora podemos obter todos os campos pelo atributo name, chamando formData.get ("input field name").

Dessa forma, você nunca precisará lidar explicitamente com o estado do formulário. Se você precisar de valores padrão (por exemplo, se alterar os valores iniciais do campo de um banco de dados ou armazenamento local), o React fornecerá uma opção conveniente defaultValue para isso.

Quando usar cada abordagem


Como os formulários são parte integrante da maioria dos aplicativos da Web, é importante saber como lidar com eles. E o React fornece várias maneiras de fazer isso.
Para formulários simples que não exigem validação rigorosa (ou que podem confiar nos controles de validação de formulário HTML5 ), sugiro que você simplesmente use o tratamento de estado interno que o DOM nos fornece por padrão. Existem algumas coisas que você não pode fazer (por exemplo, alterar programaticamente os valores de entrada ou verificar em tempo real), mas nos casos mais simples (por exemplo, um campo de pesquisa ou um campo de login, conforme indicado acima), você provavelmente achará adequado nossa abordagem alternativa usando a API do navegador.

Quando você executa uma verificação personalizada ou precisa acessar alguns dados do formulário antes de enviá-la, precisa processar explicitamente o estado usando componentes controlados. Você pode usar o useStateHooks regular ou criar um gancho personalizado para simplificar um pouco o seu código.

É importante notar que os desenvolvedores do React recomendam o uso de componentes controlados (manipule explicitamente o estado do componente) na maioria dos casos - já que essa abordagem oferece mais flexibilidade no futuro. Na minha opinião, os desenvolvedores costumam sacrificar a simplicidade por uma questão de flexibilidade, da qual eles geralmente não precisam.

Qualquer que seja a abordagem que você decida usar, o processamento do formulário React nunca foi tão fácil como é hoje. Você pode deixar o navegador manipular formulários simples e, ao mesmo tempo, processar explicitamente o estado dos formulários quando a situação exigir. Espero que os métodos acima sejam úteis e ajudem a resolver o problema, reduzindo o número de linhas no seu código.

All Articles