Executando verificação de segurança...
6

Criando mascara para input com React e useForm

Fala galera!

Recentemente eu precisei trabalhar com máscara no React com TypeScript e tive alguns problemas ao usar a lib ReactInputMask.

Recebi o Error
Overload 1 of 2, '(props: Props | Readonly<Props>): ReactInputMask', gave the following error. Type '(inputProps: any) => JSX.Element' is not assignable to type 'ReactI18NextChild | Iterable<ReactI18NextChild>'. Overload 2 of 2, '(props: Props, context: any): ReactInputMask', gave the following error.Type '(inputProps: any) => JSX.Element' is not assignable to type 'ReactI18NextChild | Iterable<ReactI18NextChild>'.

Então decidi postar aqui a solução que encontrei utilizando o regex e acredito que poderá ajudá-los em alguma ocasião.

Primeiro vamos criar uma pasta chamada MASKS e dentro dela criaremos um arquivo chamado MASK.TS, para criarmos a função que fará a máscara.

Agora dentro do arquivo mask.ts vamos criar a duas funções que serão nossas mascaras “cnpj, telefone e cep” , no caso do TypeScript, precisaremos passar um type para o parâmetro da nossa função, nesse caso passaremos a tipagem com String ou undefined.

No início da função iremos verificar se existe algum valor dentro do nosso parâmetro, caso não exista daremos um return vazio e sairemos da função, caso exista valor faremos todo o regex até termos o resultado que gostaríamos

export const normalizePhoneNumber = (value: String | undefined) => {
    if (!value) return ''
    
    return value.replace(/[\D]/g, '')
        .replace(/(\d{2})(\d)/, '($1) $2')
        .replace(/(\d{5})(\d)/, '$1-$2')
        .replace(/(-\d{4})(\d+?)/, '$1')
}

export const normalizeCnpjNumber = (value: String | undefined) => {
    if (!value) return ''
    
    return value.replace(/[\D]/g, '')
        .replace(/(\d{2})(\d)/, '$1.$2')
        .replace(/(\d{3})(\d)/, '$1.$2')
        .replace(/(\d{3})(\d)/, '$1/$2')
        .replace(/(\d{4})(\d)/, '$1-$2')
        .replace(/(-\d{2})\d+?$/, '$1')
}

export const normalizeCepNumber = (value: String | undefined) => {
    if (!value) return ''
    return value.replace(/\D/g, "")
    .replace(/^(\d{5})(\d{3})+?$/, "$1-$2")
    .replace(/(-\d{3})(\d+?)/, '$1')    
}

O próximo passo será importa a função onde precisaremos usar a máscara. No meu caso estava usando a lib react-use-form então precisei utilizar a função watch do proprio useForm para conseguir escutar quando esse campo recebe um valor e a função setValue para setar o valor para a mesma variável dentro do useForm.

import {useForm} from 'react-hook-form'

import { normalizePhoneNumber, normalizeCnpjNumber, normalizeCepNumber } from '../../Mask/mask'

const App = () => {
  const {handleSubmit, watch,setValue } = useForm<FormValues>()
  
  const onSubmit = handleSubmit((data) => console.log(data))
 
  const phoneValue = watch("phone")
  const cnpjValue = watch("cnpj")
  const cepValue = watch("cep")
  
  useEffect(() => {
    setValue("phone", normalizePhoneNumber(phoneValue))
  },[phoneValue])
  
  useEffect(() => {
    setValue("cnpj", normalizeCnpjNumber(cnpjValue))
  },[cnpjValue])
  
  useEffect(() => {
    setValue("cep", normalizeCepNumber(cepValue))
  },[cepValue])
  
  return (
    <form onSubmit={onSubmit}>
           <input {...register("cnpj", {required: true})} />
           <input {...register("phone", {required: true})} />
           <input {...register("cep", {required: true})} />
    </form>
  )
}
Carregando publicação patrocinada...
2
1
1

Se alguém precisar do código pro cpf, é só seguir a lógica:

export const normalizeCpfNumber = (value: String | undefined) => {
    if (!value) return "";

    return value
        .replace(/[\D]/g, "")
        .replace(/(\d{3})(\d)/, "$1.$2")
        .replace(/(\d{3})(\d)/, "$1.$2")
        .replace(/(\d{3})(\d)/, "$1-$2")
        .replace(/(-\d{2})\d+?$/, "$1");
};

const cpfValue = watch("cpf");

useEffect(() => {
    setValue("cpf", normalizeCpfNumber(cpfValue));
}, [cpfValue]);
1

Ola man, top seu artigo. precisei de algo simple e que resolverce meu problema e seu artigo me ajudou. eu peguei seu codigo acresentei o que eu precisava e deu sucesso.

  if (!value) return ''

  return value
    .replace(/[\D]/g, '')
    .replace(/(\d{2})(\d)/, '$1/$2')
    .replace(/(\d{2})(\d)/, '$1/$2')
    .replace(/(\d{4})(\d)/, '$1')
}


  useEffect(() => {
    form.setValue('datadosorteio', normalizeDataString(dateString))
  }, [dateString])
1
1
1
1

Obrigada, Rodrigo.
Passei um dia inteiro testando bibliotecas que pudesse usar com o react hook form para criar uma máscara de telefone, nem vídeo achei. Encontrei outros tipos de máscaras e explicações, mas sempre dava algum erro. Sua explicação me salvou.

1

Top de mais cara. Tava precisando de algo extamente assim.
Eu não tava enentendendo como eu iria manipular o valor, não conhecia esse watch do useForm.

Eu so acrecentaria para mascara de telefone o numero do pais (+55 ...), pois ai podemos pega telefone de qualquer lugar.

Mas em fim, ta show o código.
TabNews ficando melhor que o stackoverflow hehhehe

1
1

Olá, alguma dica para formularios maiores, no caso tenho um formulario com remetente e destinatario, fora outras dados, e tem dois cpf/cpnj, dois celulares e telefones, vários selects, cep validando se é válido, e um card
se usar o watch, acaba ficando muito pesado, alguma solução para não usar o watch?

1

Bem, já faz bastante tempo que você postou isso, mas estava procurando como fazer justamente isso nesse post, não encontrei aqui mas acabei descobrindo.

Daria para fazer assim:

<input {...register("cnpj", {required: true, onChange: e => e.target.value = normalizeCnpjNumber(e.target.value) })} />

Espero que você já tenha resolvido, mas fica aqui a resposta.

0
0