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} /> ); }
このロジックは一見すると良さそうに見えますが、すでに試したことがある方は、予期せぬ奇妙な動作が多く発生し、ユーザー エクスペリエンスがまったく良くないことをご存知でしょう!
もう 1 つのアプローチは、標準 HTML を使用することです。 min、max、maxLength などの属性を使用した組み込みの検証を備えた要素。ただし、通常実装したい即時フィードバックや入力制限が欠けています。
結局、Google で 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 中国語 Web サイトの他の関連記事を参照してください。