Em desenvolvimento web, especialmente para aplicações que exigem interação constante com dados numéricos, proporcionar uma experiência de usuário fluida e livre de erros é crucial. Um Componente React de input numérico bem projetado não só facilita a interação do usuário, mas também garante que os dados inseridos sejam válidos e formatados corretamente. Este artigo explora um componente React chamado CustomNumberInput, projetado para lidar com inputs numéricos de forma eficiente e melhorar a experiência do usuário.
O componente CustomNumberInput é um campo de input customizado que permite aos usuários inserir números, incluindo valores decimais e negativos. Ele assegura que os dados inseridos sigam regras de formatação específicas, como o número máximo de dígitos inteiros e decimais. Além disso, ele automaticamente lida com a validação e formatação dos valores inseridos, reduzindo a probabilidade de erros e melhorando a usabilidade.
Um exemplo rápido de como você pode usar o componente CustomNumberInput em sua aplicação:
“`javascript
import { CustomNumberInput } from ‘./CustomNumberInput’;
function App() {
const handleNumberChange = (value: string | null) => {
console.log(“Entered value:”, value);
};
return (
);
}
export default App;
“`
Neste exemplo, o Componente React de input numérico CustomNumberInput é usado para permitir que os usuários insiram um número com até 5 dígitos inteiros e 2 dígitos decimais. A prop onChange é usada para lidar com o valor inserido, que é registrado no console.
## Principais Características do Componente React de Input Numérico
O componente CustomNumberInput oferece diversas funcionalidades importantes para garantir a qualidade e a usabilidade dos dados inseridos.
1. Formatação de Números: O componente garante que os números inseridos sejam formatados corretamente, incluindo o tratamento de sinais negativos e positivos, bem como separadores decimais.
2. Validação de Input: Apenas caracteres numéricos, sinais de mais e menos, e separadores decimais são permitidos. Isso impede que os usuários insiram caracteres inválidos.
3. Controle de Dígitos: O componente permite que você defina o número máximo de dígitos inteiros e decimais que podem ser inseridos, o que é útil para aplicações que exigem precisão numérica.
4. Tratamento de Eventos: O componente lida com eventos de teclado (onKeyDown) e de mudança (onChange) para garantir que o input do usuário seja validado e formatado em tempo real.
### Lógica do Componente e Formatação de Valor
A função formatValue é o núcleo do componente. Ela formata o valor inserido pelo usuário de acordo com as regras definidas. Aqui está um resumo do que ela faz:
* Remoção de Caracteres Inválidos: Utiliza uma expressão regular para remover qualquer caractere que não seja um dígito, um sinal de mais ou menos, ou um separador decimal.
“`javascript
let formatted = input.replace(/[^\d-+,.]/, “”)
“`
* Tratamento de Sinais Negativos e Positivos: Assegura que o sinal negativo esteja corretamente posicionado e que sinais positivos não afetem o valor final.
“`javascript
if (formatted.includes(“-“)) {
formatted = formatted.replace(/-/g, “”)
formatted = formatted.startsWith(“-“) ? formatted : `-${formatted}`
}
“`
* Tratamento de Separadores Decimais: Converte qualquer separador decimal (ponto ou vírgula) em um ponto decimal padrão e limita o número de dígitos decimais com base na precisão definida.
“`javascript
if (formatted.includes(“.”) || formatted.includes(“,”)) {
formatted = formatted.replace(“.”, DECIMAL_SEPARATOR)
formatted = formatted.replace(“,”, DECIMAL_SEPARATOR)
const [intPart, …rest] = formatted.split(DECIMAL_SEPARATOR)
const decPart = rest.join(“”)
const limitedDecPart = decPart.slice(0, decimalPrecision.decimalDigits)
const formattedIntPart = !intPart || intPart === “-” ? `0${intPart}` : intPart
formatted = `${formattedIntPart}${DECIMAL_SEPARATOR}${limitedDecPart}`
}
“`
* Limitação de Dígitos Inteiros: Limita o número de dígitos inteiros que podem ser inseridos, garantindo que o limite definido não seja excedido.
“`javascript
const isNegative = formatted.startsWith(“-“)
const digits = isNegative ? formatted.slice(1) : formatted
if (digits.length > decimalPrecision.integerDigits) {
formatted = isNegative
? `-${digits.slice(0, decimalPrecision.integerDigits)}`
: digits.slice(0, decimalPrecision.integerDigits)
}
“`
### Tratamento de Eventos de Teclado
A função handleKeyDown garante que apenas teclas específicas relacionadas ao input numérico sejam permitidas. Isso inclui teclas de navegação (como setas esquerda e direita), teclas de edição (como Backspace e Delete), e caracteres numéricos. Se o usuário tentar inserir um caractere não permitido, o evento é prevenido, e o caractere não aparece no campo de input.
“`javascript
const handleKeyDown = (e: React.KeyboardEvent) => {
const allowedKeys = [
“Backspace”, “Delete”, “ArrowLeft”, “ArrowRight”,
“Tab”, “Home”, “End”, “-“, “+”, “.”, “,”, “0”,
“1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”
]
if (!allowedKeys.includes(e.key)) {
e.preventDefault()
} else if (valueInput.includes(DECIMAL_SEPARATOR) && (e.key === “.” || e.key === “,”)) {
e.preventDefault()
}
}
“`
### Tratamento de Mudanças
A função handleChange é acionada sempre que o usuário modifica o valor do campo de input. Esta função chama formatValue para formatar o valor inserido e, em seguida, atualiza o estado do componente com o valor formatado. Além disso, notifica o componente pai (através da prop onChange) do novo valor, permitindo uma integração perfeita com outros componentes.
“`javascript
const handleChange = (e: React.ChangeEvent) => {
const newValue = formatValue(e.target.value)
setValueInput(newValue)
onChange?.(newValue === ” ? null : newValue)
}
“`
O componente CustomNumberInput foi criado para melhorar a experiência do usuário ao inserir números em uma aplicação. Ao lidar automaticamente com a validação e formatação, ele reduz a carga cognitiva sobre o usuário e minimiza erros de input. Isso é especialmente útil em contextos financeiros, científicos ou qualquer outro onde a precisão numérica é crítica. Se você busca outras ferramentas, veja como iniciar seu primeiro projeto de IA com o método RICE: alcance, impacto, confiança e esforço.
Você pode ajustar o número de dígitos inteiros e decimais permitidos, e pode estender sua funcionalidade para atender a necessidades específicas. Usuários da Xiaomi poderão usar iMessage em breve.
Aqui está o código completo para o componente CustomNumberInput:
“`javascript
import * as React from “react”
import { type ClassValue, clsx } from “clsx”;
import { twMerge } from “tailwind-merge”;
type DecimalPrecision = {
integerDigits: number
decimalDigits: number
}
export interface CustomNumberInputProps
extends Omit, ‘onChange’> {
className?: string,
decimalPrecision?: DecimalPrecision
onChange?: (value: string | null) => void
}
const DEFAULT_PRECISION: DecimalPrecision = {
integerDigits: 10,
decimalDigits: 2
}
const DECIMAL_SEPARATOR = “.”
const CustomNumberInput = React.forwardRef(
({
className,
decimalPrecision = DEFAULT_PRECISION,
onChange,
…props
}, ref) => {
const [valueInput, setValueInput] = React.useState(“”)
const formatValue = React.useCallback((input: string): string => {
let formatted = input.replace(/[^\d-+,.]/, “”)
if (formatted.includes(“-“)) {
formatted = formatted.replace(/-/g, “”)
formatted = formatted.startsWith(“-“) ? formatted : `-${formatted}`
}
if (formatted.includes(“+”)) {
formatted = formatted.replace(/-/g, “”)
formatted = formatted.replace(/\+/g, “”)
}
if (formatted.includes(“.”) || formatted.includes(“,”)) {
formatted = formatted.replace(“.”, DECIMAL_SEPARATOR)
formatted = formatted.replace(“,”, DECIMAL_SEPARATOR)
const [intPart, …rest] = formatted.split(DECIMAL_SEPARATOR)
const decPart = rest.join(“”)
const limitedDecPart = decPart.slice(0, decimalPrecision.decimalDigits)
const formattedIntPart = !intPart || intPart === “-” ? `0${intPart}` : intPart
formatted = `${formattedIntPart}${DECIMAL_SEPARATOR}${limitedDecPart}`
} else {
const isNegative = formatted.startsWith(“-“)
const digits = isNegative ? formatted.slice(1) : formatted
if (digits.length > decimalPrecision.integerDigits) {
formatted = isNegative
? `-${digits.slice(0, decimalPrecision.integerDigits)}`
: digits.slice(0, decimalPrecision.integerDigits)
}
}
return formatted
}, [decimalPrecision])
const handleKeyDown = (e: React.KeyboardEvent) => {
const allowedKeys = [
“Backspace”, “Delete”, “ArrowLeft”, “ArrowRight”,
“Tab”, “Home”, “End”, “-“, “+”, “.”, “,”, “0”,
“1”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”
]
if (!allowedKeys.includes(e.key)) {
e.preventDefault()
} else if (valueInput.includes(DECIMAL_SEPARATOR) && (e.key === “.” || e.key === “,”)) {
e.preventDefault()
}
}
const handleChange = (e: React.ChangeEvent) => {
const newValue = formatValue(e.target.value)
setValueInput(newValue)
onChange?.(newValue === ” ? null : newValue)
}
const cn = (…inputs: ClassValue[]) => {
return twMerge(clsx(inputs));
}
return (
)
}
)
CustomNumberInput.displayName = “CustomNumberInput”
export { CustomNumberInput }
“`
Este conteúdo foi auxiliado por Inteligência Artificial, mas escrito e revisado por um humano.
Via Dev.to