React Hook Form é uma das bibliotecas mais populares para lidar com entradas de formulário no ecossistema React. Fazer com que funcione corretamente pode ser complicado se você estiver usando uma biblioteca de componentes, como Material UI.
Neste guia, vamos demonstrar como usar Material UI com React Hook Form. Este tutorial também é útil se você deseja integrar algum outro Biblioteca de IU do React , como Ant Design ou Semantic UI.
Para acompanhar, você já deve ter algum contato com IU de material e React Hook Form . Não vamos nos aprofundar muito em como usar essas bibliotecas. Em vez disso, vamos nos concentrar na integração entre eles.
Para mostrar como usar a IU do Material com o React Hook Form, vamos construir um formulário completo com os componentes de entrada mais usados fornecidos pelo Material IU, incluindo:
Entrada de texto Entrada de rádio Caixa de seleção Data suspensa deslizante
O formulário também terá a funcionalidade de redefinição. Será semelhante a:
Se você é um aluno mais visual, confira o tutorial em vídeo que o acompanha:
Componente de entrada de texto
Vamos começar com um componente de formulário simples. Este componente terá apenas uma entrada de texto.
Para construir este formulário pela abordagem tradicional sem qualquer biblioteca, precisamos lidar com a mudança de entrada separadamente. Também temos que cuidar da funcionalidade de redefinição e validação nós mesmos.
Provavelmente será algo assim:
import TextField from”@ material-ui/core/TextField”; import React, {useState} de”react”; importar {botão, papel} de”@ material-ui/core”; export const FormWithoutHookForm=()=> {const [textValue, setTextValue]=useState
Form Demo
A saída será semelhante a esta:
Aqui, estamos armazenando o valor usando o gancho useState fornecido pelo próprio React:
const [textValue, setTextValue]=useState
Além disso, estamos definindo o valor da entrada em nossa função onTextChange:
const onTextChange=(e: any)=> setTextValue (e.target.value);
Se olharmos para o componente TextInput fornecido por material-ui, podemos ver que há dois objetos importantes passados para ele: value e onChange. value cuida do valor real da entrada, enquanto onChange determina o que acontece quando a entrada muda. No entanto, usamos este formulário, precisamos cuidar dessas duas coisas.
Configurando o formulário React Hooks
O React Hook Form exporta alguns utilitários do famoso useForm Hook, que você então use dentro de seus componentes de entrada.
Primeiro, importe o gancho useForm:
import {useForm} de”react-hook-form”;
Então, use o Gancho dentro do componente:
const {register}=useForm ();
Uma entrada típica pode ser parecida com esta:
Olhe com atenção aqui: passamos o registro como um valor para o ref do componente de entrada real. Toda a magia acontece nos bastidores.
reactstrap fornece um suporte semelhante chamado innerRef, que pode ser usado para passar em nosso registro para integração perfeita com o react-hook-form.
Infelizmente, este não é o caso quando usamos o Material UI; a biblioteca ainda não fornece nenhum prop semelhante para passar o registro como um valor para o prop ref.
O componente Controller
React Hook Form inclui um componente wrapper chamado Controller para trabalhar bibliotecas de componentes onde você não pode acessar o ref diretamente.
De acordo com o React docs , esta é uma propriedade de renderização-uma função que retorna um elemento React e fornece a capacidade de anexar eventos e valor ao componente.
O esqueleto deste componente Controlador especial é o seguinte:
Vamos analisar o que está acontecendo aqui:
o controle é um prop que obtemos do gancho useForm e passamos para o nome da entrada é como o React Hook Form rastreia o valor de um a entrada de renderização interna é o adereço mais importante; passamos uma função de renderização aqui
A proposta de renderização
A propriedade de renderização do Controlador é a prop mais importante de se entender. A função tem três chaves: field, fieldState e formState. Vamos nos concentrar no campo por enquanto.
O objeto de campo exporta duas coisas (entre outras): valor e onChange. Já vimos que precisamos dessas duas coisas para controlar quase todas as entradas.
Refatorando nosso formulário
Então, vamos ver se o componente Controlador realmente resolve nossos problemas. Usaremos o componente Controller e passaremos o TextInput dentro da função de renderização.
Vamos primeiro extrair o que precisamos do gancho useForm:
const {handleSubmit, reset, control}=useForm ( );
Então, use o componente Controlador na forma desta forma:
import TextField de”@ material-ui/core/TextField”; import React, {useState} de”react”; importar {botão, papel} de”@ material-ui/core”; import {Controller, useForm} de”react-hook-form”; export const FormWithHookForm=()=> {const {handleSubmit, reset, control}=useForm (); const onSubmit=(data: any)=> console.log (data); return (
); };
Este formulário funciona exatamente como o anterior. A mágica acontece graças à propriedade do campo da função de renderização fornecida pelo Controlador.
Extraindo um componente para torná-lo reutilizável
Então agora sabemos como usar o componente Controlador do React Formulário de gancho para fazer o formulário funcionar sem qualquer ref. Agora vamos extrair o componente de entrada para um componente separado para que possamos usá-lo em qualquer lugar.
Este componente comum precisará de três adereços de seu pai:
nome, a chave para o controle de entrada que é usado para obter acesso às funcionalidades do rótulo React Hook Form, o rótulo da entrada (opcional) importa TextField de”@ material-ui/core/TextField”; import {Controller} de”react-hook-form”; importar React de”react”; export const FormInputText=({nome, controle, rótulo})=> {return (()}/>); };
Usaremos este componente em nosso formulário da seguinte forma:
import {FormInputText} from”./FormInputTextGood”; export const FormWithHookForm=()=> {//resto são os mesmos que antes de retornar (
) ; };
Agora, o componente é muito mais fácil de entender e reutilizar. Vamos cuidar de algumas outras entradas também.
O componente de entrada de rádio
O segundo componente de entrada mais comum é o rádio. Há um conceito importante a ser lembrado aqui.
Se você usou a IU Radio from Material, você já sabe que precisa do componente RadioGroup como pai e um monte de opções internas, como botões de rádio individuais, como crianças:
import React from”react”; import {FormControl, FormControlLabel, FormLabel, Radio, RadioGroup,} de”@ material-ui/core”; import {Controller, useFormContext} de”react-hook-form”; import {FormInputProps} de”./FormInputProps”; const options=[{label:”Radio Option 1″, value:”1″,}, {label:”Radio Option 2″, value:”2″,},]; export const FormInputRadio: React.FC
O conceito principal é o mesmo aqui. Apenas usamos onChange e o valor do objeto de campo de funções de renderização e passamos para o RadioGroup.
Observe que não usamos o rótulo aqui. Se quiser usar isso, você precisará adicionar os componentes FormControl e FormLabel da interface do usuário do material.
Observe também que usou uma função especial, generateRadioOptions, para gerar as entradas de rádio individuais. Adicionamos as opções como uma constante dentro do componente. Você pode tê-los como adereços ou de qualquer outra forma que achar conveniente.
Suspenso
Quase qualquer formulário precisa de algum tipo de menu suspenso. O código para o componente Dropdown é o seguinte:
import React from”react”; import {FormControl, InputLabel, MenuItem, Select} de”@ material-ui/core”; import {useFormContext, Controller} de”react-hook-form”; importar {FormInputProps} de”./FormInputProps”; opções const=[{rótulo:”Opção suspensa 1″, valor:”1″,}, {rótulo:”Opção suspensa 2″, valor:”2″,},]; export const FormInputDropdown=({name, control, label})=> {const generateSelectOptions=()=> {return options.map ((option)=> {return ();}); }; return
Entrada de data
Este é um componente comum, mas especial. Na IU do material, não temos nenhum componente de data que funcione imediatamente. Precisamos aproveitar algumas bibliotecas auxiliares.
Primeiro, instale essas dependências:
yarn add @ date-io/date-fns @ 1.3.13 @ material-ui/pickers @ 3.3.10 [email protected]
Tenha cuidado com as versões. Caso contrário, você pode ter alguns problemas estranhos.
Também precisamos envolver nosso componente de entrada de dados com um invólucro especial, MuiPickersUtilsProvider. Isso injetará a funcionalidade de selecionador de data para nós.
Lembre-se de que este não é um requisito para o Formulário React Hook; é exigido pelo Material UI. Portanto, se você estiver usando qualquer outra biblioteca de design, como Ant Design ou Semantic UI, não precisa se preocupar com isso.
import React from”react”; importar DateFnsUtils de”@ date-io/date-fns”; importar {KeyboardDatePicker, MuiPickersUtilsProvider} de”@ material-ui/pickers”; import {Controller} de”react-hook-form”; const DATE_FORMAT=”dd-MMM-aa”; export const FormInputDate=({name, control, label})=> {return (
Grupo de caixas de seleção
Se você deseja usar uma caixa de seleção simples que funciona como um interruptor, é fácil de usar. Você só precisa usá-lo como os componentes anteriores, então não mostrarei a mesma coisa novamente.
No entanto, surgem complexidades quando você deseja criar um grupo de caixas de seleção e definir os valores selecionados como um matriz de itens selecionados. O principal desafio aqui é que o Material UI não fornece um componente de caixa de seleção multisseleção.
Não há um exemplo claro de como usar este componente com o React Hook Form. Para habilitar essa funcionalidade, temos que manter um estado local dos itens selecionados:
import React, {useEffect, useState} de”react”; import {Checkbox, FormControl, FormControlLabel, FormLabel} de”@ material-ui/core”; import {Controller} de”react-hook-form”; const options=[{label:”Checkbox Option 1″, value:”1″,}, {label:”Checkbox Option 2″, value:”2″,},]; export const FormInputMultiCheckbox=({name, control, setValue, label})=> {const [selectedItems, setSelectedItems]=useState
); };
Portanto, neste componente, estamos controlando o valor e onChange manualmente aqui. É por isso que dentro da função de render não estamos mais usando o campo prop. Para definir o valor, estamos usando outro novo prop denominado setValue aqui. Esta função é uma função especial de react-hook-form para definir o valor manualmente.
Você pode perguntar então por que estamos fazendo isso se estamos lidando manualmente com as entradas? A resposta é quando você está usando a forma de gancho de reação, você deseja todas as suas entradas em um só lugar. Portanto, estamos dando a este componente MultiSelectCheckbox um tratamento especial aqui para que funcione facilmente com outros componentes.
Slider
Nosso componente final é um componente Slider, que é um componente bastante comum.
O código é simples de entender, mas há um problema: a função onChange fornecida pelo Material UI não funciona com onChange of React Hook Form porque a assinatura é diferente.
Como resultado, quando tentamos usar o componente Slider dentro de um componente Controller do React Hook Form, ele gera um erro. Mais uma vez, devemos manter um estado local para controlar o onChange e definir o valor manualmente.
O código completo para este componente é o seguinte:
import React, {useEffect} from”react”; importar {Slider} de”@ material-ui/core”; import {Controller} de”react-hook-form”; export const FormInputSlider=({name, control, setValue, label})=> {const [sliderValue, setSliderValue]=React.useState (0); useEffect (()=> {if (sliderValue) setValue (name, sliderValue);}, [sliderValue]); const handleChange=(event: any, newValue: number | number [])=> {setSliderValue (newValue as number); }; return
Juntando tudo
Agora vamos usar todos esses componentes dentro do nosso formulário. Nosso formulário aproveitará todas as vantagens de todos os componentes reutilizáveis que acabamos de fabricar:
import {Button, Paper, Typography} from”@ material-ui/core”; import {FormProvider, useForm} de”react-hook-form”; import {FormInputText} de”./form-components/FormInputText”; import {FormInputMultiCheckbox} de”./form-components/FormInputMultiCheckbox”; importar {FormInputDropdown} de”./form-components/FormInputDropdown”; importar {FormInputDate} de”./form-components/FormInputDate”; importar {FormInputSlider} de”./form-components/FormInputSlider”; import {FormInputRadio} de”./form-components/FormInputRadio”; const defaultValues ={textValue:””, radioValue:””, checkboxValue: [], dateValue: new Date (), dropdownValue:””, sliderValue: 0,}; export const FormDemo=()=> {const métodos=useForm ({defaultValues: defaultValues}); const {handleSubmit, reset, control, setValue}=métodos; const onSubmit=(dados: IFormInput)=> console.log (dados); return (
Conclusão
Agora nosso formulário é muito mais limpo e com melhor desempenho. A partir daqui, podemos adicionar nossa lógica de validação de formulário e erro manipular muito facilmente.
Para brincar com este exemplo por conta própria, verifique o código completo em GitHub .