在 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 並找到了一些......駭客解決方案。
經過多次嘗試和錯誤,我終於找到了更好的方法。
我們可以利用內建的 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 驗證,並限制無效的使用者輸入數字。
查看現場範例並嘗試
我們可以透過將其提取到像這樣的自訂掛鉤中來使該邏輯更加可重複使用
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中文網其他相關文章!