Este pequeno artigo traz informações sobre conceitos abordados em React, como Imutabilidade de Estados, Forms simples e com React Hook Form e a validação Yup.
A imutabilidade de estados é um conceito na programação onde, basicamente, os Objetos não podem ter seu estado alterado após sua criação, de forma que o Objeto é descartado quando o estado é alterado. Vale dizer também que quando um atributo imutável é instanciado, seu endereço de memória não pode ser alterado e nem podem ser reinicializados. As alterações no estado são feitas através de um novo objeto, preservando sempre o original.
No React, podemos observar esse conceito na construção dos componentes, que atualizam a interface sempre que o estado de um componente muda.
- A imutabilidade de Estados melhora a segurança de dados e a eficiência do código, pois nele não é possível alterar por “acidente” um estado que está sendo compartilhado em vários threads;
- Torna possível a rastreabilidade, já que fica mais fácil monitorar como o estado evolui ao longo do tempo;
- Melhoria na performance, já que otimiza a renderização ao comparar os estados dos objetos e atualizar somente o que foi alterado.
import React, { useState } from "react";
const MyComponent = () => {
const [counter, setCounter] = useState(0);
const incrementCounter = () => {
setCounter(counter + 1);
};
return (
<div>
<h1>Counter: {counter}</h1>
<button onClick={incrementCounter}>Increment</button>
</div>
);
};
export default MyComponent;
No exemplo, o componente MyComponent usa o Hook useState para manter o estado do contador, que é imutável e não pode ser alterado diretamente, somente através da função setCounter, que recebe um novo valor para o contador e atualiza o estado do componente.
Na construção de um formulário “cru”, você cria os componentes na mão ou com alguma biblioteca, como o Material UI e a manipulação desses dados é feita através dos handlers, que são funções que alteram o estado de nome e email e são chamadas a cada vez o usuário digita algo nos campos de entrada. No caso do submit, há o prevent default para evitar o recarregamento da página e um console.log que mostra uma mensagem com os dados submetidos.
Segue abaixo um exemplo:
import React, { Component, ChangeEvent, FormEvent } from "react";
interface State {
name: string;
email: string;
}
class FormExample extends Component<{}, State> {
constructor(props: {}) {
super(props);
this.state = {
name: "",
email: "",
};
}
handleNameChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ name: event.target.value });
};
handleEmailChange = (event: ChangeEvent<HTMLInputElement>) => {
this.setState({ email: event.target.value });
};
handleSubmit = (event: FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log("Form submitted with data:", this.state);
};
render() {
return (
<div>
<h2>Form Example</h2>
<form onSubmit={this.handleSubmit}>
<div>
<label>Name:</label>
<input
type="text"
value={this.state.name}
onChange={this.handleNameChange}
/>
</div>
<div>
<label>Email:</label>
<input
type="email"
value={this.state.email}
onChange={this.handleEmailChange}
/>
</div>
<button type="submit">Submit</button>
</form>
</div>
);
}
}
export default FormExample;
O Hook Form é uma biblioteca para gerenciar formulários que utiliza de Hooks como useState e useEffect para simplificar e otimizar o processo de criação, validação e gerenciamento de formulários, porém os componentes são gerenciados pela biblioteca. Como vantagens, temos uma melhor performance, um alto grau de customização, uma integração simples e uma simples validação com tratamento de erros.
Antes de mais nada, para usar o React Hook Form, é necessário executar este comando no terminal do seu projeto:
npm install react-hook-form
E importar nos seus documentos, aplicando da seguinte forma:
import React from "react";
import { useForm } from "react-hook-form";
function FormExample() {
const { register, handleSubmit, errors } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input type="text" name="name" ref={register({ required: true })} />
{errors.name && <span>This field is required</span>}
<input
type="email"
name="email"
ref={register({ required: true, pattern: /^\S+@\S+$/i })}
/>
{errors.email && <span>Invalid email</span>}
<button type="submit">Submit</button>
</form>
);
}
export default FormExample;
O Hook Form inicia o formulário em “FormExample” e fornece os métodos:
- Register que é usado para conectar campos do formulário ao estado interno e passar algumas validações, no return é possível passar a informação “required: true” e um pattern para definir as entradas aceitas. São aceitas as seguintes validações: required, min, max, minLength, maxLength, pattern, validate.
- HandleSubmit que é usado para submissão do formulário e receber os dados;
- Errors que contém os erros de validação associados ao formulário.
Também há o Controller, iniciado com control, que é utilizado para encapsular campos de entrada controlados:
import React from "react";
import { useForm, Controller } from "react-hook-form";
function FormExample() {
const { handleSubmit, control } = useForm();
const onSubmit = (data) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="name"
control={control}
defaultValue=""
render={({ field }) => <input {...field} />}
/>
<Controller
name="email"
control={control}
defaultValue=""
render={({ field }) => <input {...field} />}
/>
<button type="submit">Submit</button>
</form>
);
}
export default FormExample;
Nele, podemos passar o nome do campo, o valor inicial do campo (defaultValue), o control que recebe o controle do formulário, o render que recebe uma função para colocar o campo em tela, passando o objeto field que contém as informações do campo.
Frequentemente empregado com React Hook Form, o YUP é uma biblioteca de validação de formulários, que fornece uma maneira simples e declarativa de definir as regras de validação para seus dados, garantindo que eles atendam as expectativas antes de serem enviados ou processados.
Antes de mais nada, para utilizar o Yup, devemos instalá-lo no projeto:
npm i yup
Com o Yup, podemos definir os Schemas,q que são esquemas para definir a estrutura dos dados de cada campo e as regras de validação associadas a ele, como o formato se é string, data, email, um número positivo, além de poder configurar mensagens e limitações ao input como torna-lo obrigatório.
const addressSchema = yup.object().shape({
email: yup
.string()
.email(“Invalid email”)
.required(“Email is required”),
fullName: yup
.string()
.required(),
houseNumber: yup
.number()
.required()
.positive()
.integer(),
address: yup
.string()
.required(),
postCode: yup
.string()
.required(),
timestamp: yup
.date()
.default(() => (new Date()),
}),});
Também podemos fazer uma validação se os dados seguem em conformidade com o schema, com o isValid, veja um exemplo completo abaixo:
function FormExample() {
const { handleSubmit, register, formState, setError } = useForm();
const onSubmit = (data) => {
addressSchema.isValid(data).then((isValid) => {
if (isValid) {
console.log("Form is valid:", data);
} else {
setError("form", {
type: "manual",
message: "Form is not valid according to schema",
});
}
});
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input type="text" name="street" placeholder="Street" ref={register} />
<input type="text" name="city" placeholder="City" ref={register} />
<input
type="text"
name="postalCode"
placeholder="Postal Code"
ref={register}
/>
{formState.errors.form && <p>{formState.errors.form.message}</p>}
<button type="submit">Submit</button>
</form>
);
}
export default FormExample;
Aqui, se o data recebe dados validos, de acordo com o schema especificado, ele entra na validação e mostra no console “Form is valid: true”, caso contrário, exibe um erro.