Maison  >  Article  >  interface Web  >  Meilleure façon de gérer la validation de la saisie des nombres dans React

Meilleure façon de gérer la validation de la saisie des nombres dans React

WBOY
WBOYoriginal
2024-09-07 06:40:021189parcourir

Gérer les entrées de nombres dans React peut être pénible, surtout lorsque vous devez vous assurer qu'ils ont la bonne taille ou qu'ils ont le bon nombre de points décimaux. Des choses simples peuvent sembler faciles, mais une fois que vous entrez dans le vif du sujet et essayez de créer des expériences utilisateur personnalisées, le code peut rapidement devenir compliqué.

Une approche courante que la plupart d'entre nous utilisent consiste à écrire la logique de validation personnalisée qui restreint la saisie de l'utilisateur dans le gestionnaire onChange.

Quelque chose comme ça

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}
    />
  );
}

Cette logique semble bonne à première vue, mais si vous l'avez déjà essayée, vous savez qu'elle s'accompagne de nombreux comportements inattendus et étranges et d'une expérience utilisateur pas du tout bonne !

Une autre approche consiste à utiliser le code HTML standard élément avec les validations intégrées utilisant des attributs tels que min, max, maxLength etc. Cependant, il lui manque le retour instantané et les restrictions de saisie que nous souhaitons habituellement implémenter.

Nous finissons par chercher sur Google notre chemin vers Stack Overflow et trouvons des solutions... hackish.

  • Utilisez onKeyPress et validez manuellement les valeurs saisies.
  • Utiliser l'attribut pattern et ajouter Regex pour valider le numéro (ce qui ne fonctionne pas avec le type="number" nous devons donc le rendre type="text" ).
  • et que sais-je encore...

Best way to handle number input validation in React

Après de nombreux essais et erreurs, j'ai finalement trouvé une meilleure façon de procéder.

La solution

Nous pouvons utiliser la validation d'entrée HTML intégrée avec du javascript personnalisé pour créer une solution parfaite.

Voici le composant

// 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}
    />
  );
}

Avec cette approche, nous pouvons utiliser les validations HTML intégrées et également restreindre les saisies utilisateur non valides pour les nombres.

Best way to handle number input validation in React

Découvrez un exemple en direct et jouez

Prime

Nous pouvons rendre cette logique plus réutilisable en l'extrayant dans un hook personnalisé comme celui-ci

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,
  };
};

Et utilisez-le dans n'importe quel composant si nécessaire (qui a évidemment un élément d'entrée).

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>
  );
}

N'hésitez pas à ajouter des commentaires et à suggérer des améliorations !

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn