首頁  >  文章  >  web前端  >  在 React 中處理數位輸入驗證的最佳方法

在 React 中處理數位輸入驗證的最佳方法

WBOY
WBOY原創
2024-09-07 06:40:021190瀏覽

在 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