Catégories
Astuces et Design

Travailler avec des formulaires dans React

Presque toutes les applications doivent accepter l'entrée de l'utilisateur à un moment donné, et cela est généralement réalisé avec le vénérable formulaire HTML et sa collection de contrôles d'entrée. Si vous avez récemment commencé à apprendre React, vous êtes probablement arrivé au point où vous vous demandez maintenant: "Comment puis-je travailler avec les formulaires?"

Cet article vous expliquera les bases de l'utilisation des formulaires dans React pour permettre aux utilisateurs d'ajouter ou de modifier des informations. Nous allons examiner deux façons différentes de travailler avec les contrôles d'entrée et les avantages et les inconvénients de chacun. Nous examinerons également comment gérer la validation et certaines bibliothèques tierces pour des cas d'utilisation plus avancés.

Entrées incontrôlées

La manière la plus basique de travailler avec des formulaires dans React est d'utiliser ce que l'on appelle des entrées de formulaire «non contrôlées». Cela signifie que React ne suit pas l’état de l’entrée. Les éléments d'entrée HTML gardent naturellement une trace de leur propre état dans le cadre du DOM, et donc lorsque le formulaire est soumis, nous devons lire les valeurs des éléments DOM eux-mêmes.

Pour ce faire, React nous permet de créer une «ref» (référence) à associer à un élément, donnant accès au nœud DOM sous-jacent. Voyons comment procéder:

class SimpleForm extends React.Component {
  constructor(props) {
    super(props);
    
    this.nameEl = React.createRef();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(e) {
    e.preventDefault();
    alert(this.nameEl.current.value);
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>Name:
          <input type="text" ref={this.nameEl} />
        label>
        <input type="submit" name="Submit" />
      form>
    )
  }
}

Comme vous pouvez le voir ci-dessus, pour un composant basé sur une classe, vous initialisez une nouvelle référence dans le constructeur en appelant React.createRef, en l'attribuant à une propriété d'occurrence afin qu'elle soit disponible pendant toute la durée de vie du composant.

Afin d'associer la référence à une entrée, elle est passée à l'élément en tant que l'élément spécial ref attribut. Une fois que cela est fait, le nœud DOM sous-jacent de l'entrée est accessible via this.nameEl.current.

Voyons à quoi cela ressemble dans un composant fonctionnel:

function SimpleForm(props) {
  const nameEl = React.useRef(null);

  const handleSubmit = e => {
    e.preventDefault();
    alert(nameEl.current.value);
  };

  return (
     <form onSubmit={handleSubmit}>
       <label>Name:
         <input type="text" ref={nameEl} />
       label>
       <input type="submit" name="Submit" />
     form>
   );
}

Il n'y a pas beaucoup de différence ici, à part l'échange createRef pour le useRef crochet.

Exemple: formulaire de connexion

function LoginForm(props) {
  const nameEl = React.useRef(null);
  const passwordEl = React.useRef(null);
  const rememberMeEl = React.useRef(null);

  const handleSubmit = e => {
    e.preventDefault();

    const data = {
      username: nameEl.current.value,
      password: passwordEl.current.value,
      rememberMe: rememberMeEl.current.checked,
    }

    
    
  };

  return (
     <form onSubmit={handleSubmit}>
       <input type="text" placeholder="username" ref={nameEl} />
       <input type="password" placeholder="password" ref={passwordEl} />
       <label>
         <input type="checkbox" ref={rememberMeEl} />
         Remember me
       label>
       <button type="submit" className="myButton">Loginbutton>
     form>
   );
}

Voir sur CodePen

Bien que les entrées non contrôlées fonctionnent correctement pour les formulaires simples et rapides, elles présentent certains inconvénients. Comme vous l'avez peut-être remarqué dans le code ci-dessus, nous devons lire la valeur de l'élément d'entrée chaque fois que nous le voulons. Cela signifie que nous ne pouvons pas fournir une validation instantanée sur le champ au fur et à mesure que l'utilisateur tape, ni faire des choses comme appliquer un format d'entrée personnalisé, afficher ou masquer sous condition des éléments de formulaire ou désactiver / activer le bouton d'envoi.

Heureusement, il existe un moyen plus sophistiqué de gérer les entrées dans React.

Entrées contrôlées

Une entrée est dite «contrôlée» lorsque React est responsable du maintien et du réglage de son état. L’état est synchronisé avec la valeur de l’entrée, ce qui signifie que la modification de l’entrée mettra à jour l’état et la mise à jour de l’état modifiera l’entrée.

Voyons à quoi cela ressemble avec un exemple:

class ControlledInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: '' };
    this.handleInput = this.handleInput.bind(this);
  }

  handleInput(event) {
    this.setState({
      name: event.target.value
    });
  }

  render() {
    return (
      <input type="text" value={this.state.name} onChange={this.handleInput} />
    );
  }
}

Comme vous pouvez le voir, nous avons mis en place une sorte de flux de données circulaire: état en valeur d'entrée, sur changement d'événement en état, et inversement. Cette boucle nous permet beaucoup de contrôle sur l'entrée, car nous pouvons réagir aux changements de valeur à la volée. Pour cette raison, les entrées contrôlées ne souffrent pas des limitations des entrées non contrôlées, ce qui ouvre les possibilités suivantes:

  • validation d'entrée instantanée: nous pouvons donner un retour instantané à l'utilisateur sans avoir à attendre qu'il soumette le formulaire (par exemple si son mot de passe n'est pas assez complexe)
  • formatage d'entrée instantané: nous pouvons ajouter des séparateurs appropriés aux entrées de devises, ou regrouper les numéros de téléphone à la volée
  • désactiver conditionnellement la soumission du formulaire: nous pouvons activer le bouton d'envoi une fois que certains critères sont remplis (par exemple, l'utilisateur a consenti aux termes et conditions)
  • générer dynamiquement de nouvelles entrées: nous pouvons ajouter des entrées supplémentaires à un formulaire en fonction de l'entrée précédente de l'utilisateur (par exemple, ajouter des détails sur des personnes supplémentaires lors d'une réservation d'hôtel)

Validation

Comme je l'ai mentionné ci-dessus, la boucle de mise à jour continue des composants contrôlés permet d'effectuer une validation continue sur les entrées au fur et à mesure que l'utilisateur tape. Un gestionnaire attaché à une entrée onChange L'événement sera déclenché à chaque frappe, vous permettant de valider ou de formater instantanément la valeur.

Exemple: validation de carte de crédit

Jetons un œil à un exemple concret de vérification d'un numéro de carte de crédit lorsque l'utilisateur le saisit dans un formulaire de paiement.

L'exemple utilise une bibliothèque appelée type de carte de crédit pour déterminer l'émetteur de la carte (comme Amex, Visa ou Mastercard) comme type d'utilisateur. Le composant utilise ensuite ces informations pour afficher une image du logo de l'émetteur à côté de l'entrée:

import  creditCardType  from  "credit-card-type";

function CreditCardForm(props) {
  const (cardNumber, setCardNumber) = React.useState("");
  const (cardTypeImage, setCardTypeImage) = React.useState(
    "card-logo-unknown.svg"
  );

  const handleCardNumber = (e) => {
    e.preventDefault();

    const value = e.target.value;
    setCardNumber(value);

    let suggestion;

    if (value.length > 0) {
      suggestion = creditCardType(e.target.value)(0);
    }

    const cardType = suggestion ? suggestion.type : "unknown";

    let imageUrl;

    switch (cardType) {
      case "visa":
        imageUrl = "card-logo-visa.svg";
        break;
      case "mastercard":
        imageUrl = "card-logo-mastercard.svg";
        break;
      case "american-express":
        imageUrl = "card-logo-amex.svg";
        break;
      default:
        imageUrl = "card-logo-unknown.svg";
    }

    setCardTypeImage(imageUrl);
  };

  return (
    <form>
      <div className="card-number">
        <input
          type="text"
          placeholder="card number"
          value={cardNumber}
          onChange={handleCardNumber}
        />
        <img src={cardTypeImage} alt="card logo" />
      div>
      <button type="submit" className="myButton">
        Login
      button>
    form>
  );
}

L'entrée est onChange handler appelle le creditCardType() fonction avec la valeur actuelle. Cela renvoie un tableau de correspondances (ou un tableau vide) qui peut être utilisé pour déterminer quelle image afficher. L'URL de l'image est ensuite définie sur une variable d'état à restituer dans le formulaire.

Vous pouvez utiliser certains des nombres d'ici pour tester l'entrée.

Bibliothèques de formulaires

Comme vous l'avez peut-être remarqué, il existe une certaine quantité de code passe-partout lorsque vous travaillez avec des formulaires, en particulier lorsque vous devez câbler les entrées avec leurs valeurs d'état et leurs gestionnaires. Comme vous vous en doutez, il existe une variété de bibliothèques tierces pour vous aider à vous débarrasser de la douleur liée au traitement de formulaires plus volumineux et plus complexes.

Pour vous donner une idée de l'utilisation d'une bibliothèque de formulaires, jetons un coup d'œil à celle appelée Fresh. Le but de cette bibliothèque est de couvrir 90% de vos cas d'utilisation courants avec une API simple et facile à utiliser. Voici un exemple de formulaire de modification de profil que vous pourriez trouver dans une application Web:

import { Form, Field } from "@leveluptuts/fresh";

const securityQuestions = (
  "What is your mother's maiden name?",
  "What was the name of your first pet?",
  "What was the name of your first school?"
);

const handleSubmit = (data) => console.log(data);

function UserProfileForm() {
  return (
    <Form formId="user-profile" onSubmit={handleSubmit}>
      <Field required>First NameField>
      <Field required>Last NameField>
      <Field required type="email">
        Email
      Field>

      <Field required type="select" options={securityQuestions}>
        Security Question
      Field>
      <Field required>Security AnswerField>

      <Field type="textarea">BioField>
    Form>
  );
}

Fresh fournit des composants personnalisés pour rendre la création de formulaires très simple. le Field Le composant prend en charge le câblage de la liaison des données sur les entrées du formulaire, convertissant l'étiquette que vous fournissez en un nom de propriété en cas de chameau pour la valeur de l'entrée. (Par exemple, "Nom de famille" devient lastName dans l'état du formulaire.)

le Form composant encapsule tous les champs et prend un onSubmit callback qui reçoit les données du formulaire en tant qu'objet. Voici un exemple de la sortie du formulaire:

{
  firstName: "Bill",
  lastName: "Gates",
  email: "billg@microsoft.com",
  securityQuestion: "What was the name of your first pet?",
  securityAnswer: "Fluffy",
  bio: "Bill Gates is a technologist, business leader, and philanthropist. He grew up in Seattle, Washington, with an amazing and supportive family who encouraged his interest in computers at an early age."
}

Comme vous pouvez le voir, des bibliothèques comme celle-ci peuvent vraiment accélérer le travail avec les formulaires et rendre vos composants beaucoup moins verbeux. Pour tout ce qui est plus qu'un petit formulaire basique, je vous recommande d'en choisir un qui correspond à vos besoins, car il vous fera gagner du temps à long terme.

Conclusion

Vous devriez maintenant avoir une solide compréhension de la façon dont les formulaires et les entrées peuvent être utilisés dans React. Vous devez connaître la différence entre les entrées contrôlées et non contrôlées, ainsi que les avantages et les inconvénients de chacune, sachant que la boucle de mise à jour étroite d'une entrée contrôlée vous permet de nombreuses options de formatage et de validation des valeurs à la volée. Enfin, vous devez savoir qu'il existe des bibliothèques de formulaires disponibles qui vous évitent d'avoir à ajouter beaucoup de code réutilisable répétitif et détaillé à vos formulaires React, ce qui vous aidera à être un développeur plus productif.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *