首页  >  文章  >  web前端  >  在 React 中处理数字输入验证的最佳方法

在 React 中处理数字输入验证的最佳方法

WBOY
WBOY原创
2024-09-07 06:40:021160浏览

在 React 中处理数字输入可能会很痛苦,尤其是当您需要确保它们的大小正确或具有正确的小数位数时。简单的东西可能看起来很容易,但是一旦您深入了解本质并尝试实现自定义用户体验,代码可能会很快变得混乱。

我们大多数人使用的常见方法是编写自定义验证逻辑来​​限制 onChange 处理程序中的用户输入。

类似这样的

function NumberInput({
  value,
  onChange,
  min,
  max,
}: {
  value: number;
  onChange: (val: number) => void;
  min?: number;
  max?: number;
}) {
  const changeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
    const val = +e.target.value;
    if (min != null && val < min) {
      onChange(min);
      return;
    }
    if (max != null && val > max) {
      onChange(max);
      return;
    }
    onChange(val);
  };

  return (
    <input
      type="number"
      value={value}
      onChange={changeHandler}
    />
  );
}

这个逻辑乍一看似乎不错,但如果你已经尝试过了,你就会知道它会带来很多意想不到和奇怪的行为,而且根本不是一个好的用户体验!

另一种方法是使用标准 HTML 使用 min、max、maxLength 等属性进行内置验证的元素。但是,它缺乏我们通常想要实现的即时反馈和输入限制。

我们最终通过谷歌搜索 Stack Overflow 并找到了一些......黑客解决方案。

  • 使用 onKeyPress 并手动验证输入值。
  • 使用模式属性并添加正则表达式来验证数字(这不适用于 type="number",因此我们必须将其设置为 type="text")。
  • 还有什么......

Best way to handle number input validation in React

经过多次尝试和错误,我终于找到了更好的方法。

解决方案

我们可以利用内置的 HTML 输入验证和一些自定义 JavaScript 来构建完美的解决方案。

这是组件

// Interface for props overriding the default value and onChange
// attribute to accept only numeric value
export interface NumberInputProps
  extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "onChange"> {
  onChange: (val: number) => void;
  value: number;
}

function NumberInput({
  value,
  onChange,
  min,
  max,
  step,
  ...props
}: NumberInputProps) {
  // Internal input state to avoid weird behaviors with empty inputs
  const [input, setInput] = React.useState(value?.toString() || "");

  const changeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
    // Using HTML input validity API to validation
    if (
      (max != null && e.target.validity.rangeOverflow) ||
      (min != null && e.target.validity.rangeUnderflow) ||
      (step != null && e.target.validity.stepMismatch)
    )
      return;

    const val = +e.target.value;
    setInput(e.target.value);
    onChange(val);
  };

  // To ensure the external updates are reflected in the input element
  React.useEffect(() => {
    setInput(value.toString());
  }, [value]);

  return (
    <Input
      ref={ref}
      type="number"
      value={input}
      onChange={changeHandler}
      min={min}
      max={max}
      step={step}
      {...props}
    />
  );
}

通过这种方法,我们可以利用内置的 HTML 验证,并限制无效的用户输入数字。

Best way to handle number input validation in React

查看现场示例并尝试一下

奖金

我们可以通过将其提取到像这样的自定义挂钩中来使该逻辑更加可重用

export const useNumberInput = ({
  value,
  onChange,
  min,
  max,
  step,
}: {
  value: number;
  onChange: (val: number) => void;
  max?: number;
  min?: number;
  step?: number;
}): InputHTMLAttributes<HTMLInputElement> => {
  const [input, setInput] = useState(value?.toString() || "");

  const changeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
    if (
      (max != null && e.target.validity.rangeOverflow) ||
      (min != null && e.target.validity.rangeUnderflow) ||
      (step != null && e.target.validity.stepMismatch)
    )
      return;

    const val = +e.target.value;
    setInput(e.target.value);
    onChange(val);
  };

  useEffect(() => {
    setInput(value.toString());
  }, [value]);

  return {
    type: "number",
    value: input,
    onChange: changeHandler,
    min,
    max,
    step,
  };
};

并在任何需要的组件中使用它(显然有一个输入元素)。

export default function CustomInput() {
  const [value, setValue] = useState(0);
  const inputProps = useNumberInput({
    value,
    onChange: setValue,
    min: 1,
    max: 50,
  });

  return (
    <div>
      <button onClick={() => onChange(value + 1)}>
        +
      </button>
      <button onClick={() => onChange(value - 1)}>
        -
      </button>
      <input
        {...inputProps}
        {...otherProps}
      />
    </div>
  );
}

请随意添加评论并提出改进建议!

以上是在 React 中处理数字输入验证的最佳方法的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn