react_lecon_1

React.js fournit deux manières de récupérer les valeurs depuis les éléments.

La première méthode consiste à implémenter ce qu’on appelle les “controlled components” (voir ce billet sur le sujet) et la seconde est d’utiliser la propriété ref de React.

Les “Controlled components” sont assez lourds à mettre en place. La définition des caractéristiques d’un controlled component est que la valeur affichée est liée à l’état du component . Pour mettre à jour la valeur on execute une fonction attachée à l’écouteur onChange sur l’élément form. La fonction onChange met à jour l’état de la propriété, qui à son tour met à jour la valeur de l’élément form.

(Avant de s’enfoncer plus loin, si vous voulez juste voir les extraits de code de cet article: c’est par içi!)

Voici un exemple de controlled component:


import React, { Component } from 'react';

class ControlledCompExample extends Component {
	constructor() {
		super();
		this.state = {
			fullName: ''
		}
	}
	handleFullNameChange = (e) => {
		this.setState({
			fullName: e.target.value
		})
	}
	handleSubmit = (e) => {
		e.preventDefault();
		console.log(this.state.fullName)
	}
	render() {
		return (
		<div>
			<form onSubmit={this.handleSubmit}>
				<label>Full Name</label>
				<input name="fullName" type="text" value="{this.state.fullName}" />
				<input type="submit" value="Submit" />
			</form>
		</div>
		);
	}
} export default ControlledCompExample;

La valeur du champ d’entrée est this.state.fullName (lignes 7 and 26). La fonction onChange est:
 handleFullNameChange (lignes 10 – 14, et ligne 27).

Le principal avantage des controlled components est:

  1. Vous pouvez facilement  valider les entrées de l’utilisateur.
  2. Vous pouvez afficher dynamiquement les autres composants par rapport à la valeur du  controlled component. Par exemple, la valeur qu’un utilisateur sélectionne dans une liste déroulante (comme ‘dog’ ou ‘cat’) peut contrôler la façon dont un autre composant sera affiché dans le formulaire.

La contrepartie des controlled components  est la quantité de code à écrire. Il vous faut une propriété d’état à passer à l’élément form comme props, et il vaut faut également une fonction pour mettre à jour la valeur de cette propriété.

Pour un élément form ce n’est pas un problème – mais si vous avez un formulaire complexe (qui ne nécessite pas d’affichage dynamique ou de validation d’entrée en temps réel) vous allez devoir écrire une tonne de code si vous utilise trop les controlled components.

Une façon plus simple et moins nécessiteuse de travail pour récupérer les valeurs d’un élément form est d’utiliser la propriété  ref . Différents composants et éléments form composés nécessitent des stratégies différentes , donc le reste de ce billet est divisé en plusieurs sections, à savoir:

  1. Champs d’entrée text, number et selects
  2. Passer les propriétés d’un enfant à son parent
  3. Les boutons radios
  4. Les Checkboxs

1. Champs d’entrée text, number et selects

Les champs d’entrée Text et number nous donnent le meilleur exemple d’utilisation des refs. Dans l’attribut ref du champ d’entrée, ajoutez une fonction fléchée qui prend l’entrée en argument. Essayez d’utiliser la même dénomination pour l’argument et l’élémént lui même comme ci-dessous:

<input type="text" ref={input => this.fullName = input} />

Comme c’est un alias pour l’élément input lui même, vous pouvez nommer l’argument comme vous l’entendez:

<input type="number" ref={cashMoney => this.amount = cashMoney} />

Ensuite vous prenez l’argument et l’assignez à une propriété attachée à la classe this mot-clef. Les entrées (noeuds du DOM) sont maintenant accessibles via this.fullName et this.amount. Les valeurs des inputs sont accessibles via this.fullName.value et this.amount.value.
La même stratégie est applicable pour les éléments select (ex. listes déroulantes).

<select
	ref={select => this.petType = select}
	name="petType">
	<option value="cat">Cat</option>
	<option value="dog">Dog</option>
	<option value="ferret">Ferret</option>
</select>

La valeur sélectionnée est accessible via this.petType.value.

2. Passer les propriétés d’un enfant à son parent

Avec un controlled component, assigner la valeur d’un composant enfant à un parent est assez facile – cette dernière existe déjà dans le parent! Elle est passée à l’enfant. Une fonction onChange lui est aussi passée et met à jour la valeur au fur et à mesure que l’utilisateur interagit avec l’interface utilisateur(UI).

Vous pouvez le voir en action dans l’exemple suivant.

Alors que la valeur existe déjà dans l’état du parent quand on utilise un controlled component, ce n’es pas le cas quand on utilise refs. Avec les refs, la valeur réside dans le noeud DOM lui même et doit être communiquée jusqu’au parent.

Pour passer cette valeur depuis l’enfant jusqu’au parent, le parent doit lui passer un ‘hook'(crochet). L’enfant attache alors un noeud au ‘crochet'(hook) de telle sorte que le parent puisse y accéder.

Regardons un petit exemple, avant de d’en discuter plus en profondeur.

import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();
    console.log('first name:', this.firstName.value);
    this.firstName.value = 'Got ya!';
  }
  render() {
    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <CustomInput
            label={'Name'}
            firstName={input => this.firstName = input} />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

function CustomInput(props) {
  return (
    <div>
      <label>{props.label}:</label>
      <input type="text" ref={props.firstName}/>
    </div>
  );
}

export default RefsForm;

Ci-dessus on voit un composant RefForm, et un composant d’entrée appelé CustomInput. Habituellement, une fonction fléchée est sur l’input lui même, mais içi elle est passée comme une propriété (voir lignes 15 et 27). Comme la fonction fléchée réside dans le parent, le this de this.firstName existe dans le parent.

La valeur de l’input enfant est assignée au this.firstName propriété du parent, de sorte que la valeur de l’enfant soit accessible au parent. Maintenant, dans le parent, this.firstName fait référence à un noeud du DOM dans le composant enfant ( le input dans CustomInput).

Non seulement le noeud du DOM de l’input est accessible par le parent, mais la valeur du noeud l’est aussi depuis le parent. Ceci est démontré à la ligne 7 ci-dessus. Une fois le formulaire envoyé, la valeur de l’input vaut ‘Got ya!’.

Ce schéma est un peu compliqué donc n’hésitez pas à y passer du temps et à jouer un peu avec le code jusqu’à ce que vous compreniez bien.

Il est préférable de faire des controlled components à base de radios et de checkboxs, mais si vous voulez vraiment utiliser les refs alors, les deux prochaines sections sont pour VOUS!

3. Les boutons radios

Contrairement au éléments ‘input’ text et number, les boutons radios existent par ‘lot’. Chaque élément dans un ‘lot’ a le même attribut name , comme ceci:

<form>
  <label>
    Cat
    <input type="radio" value="cat" name="pet" />
  </label>
  <label>
    Dog
    <input type="radio" value="dog" name="pet" />
  </label>
  <label>
    Ferret
    <input type="radio" value="ferret" name="pet" />
  </label>
  <input type="submit" value="Submit" />
</form>

Il y a trois options dans le ‘lot’ de radios “pet” – “cat”, “dog”, et “ferret”.

Comme l’intégralité du ‘lot’ est l’objet de notre attention mettre en place un ref sur chaque input ‘radio’ input n’est pas idéal. Et malheureusement, il n’y a pas de noeud dans le DOM qui encapsule un ‘lot’ de radios.

La valeur d’un lot de ‘radio’ peut être récupérée en suivant trois étapes:

  1. Assigner un ref à l’élément <form> (ligne 20 ci-dessous).
  2. Extraire le ‘lot’ de radios depuis le formulaire. Dans ce cas, c’est le lot pet (ligne 9 ci-dessous).
    • Une liste de noeuds et une valeur est retournée içi. Dans ce cas, cette liste de noeuds comprend trois noeuds d’entrée, et la valeur sélectionnée.
    • Gardez à l’esprit qu’une liste de noeuds ressemble à un array mais n’en est pas un, elle ne comprend donc pas les méthodes de ces derniers. Nous reviendrons sur le sujet dans la prochaine section.
  3. Récupérer la valeur du ‘lot’ en utilisant la notation ‘point'(ligne 13 ci-dessous).
import React, { Component } from 'react';

class RefsForm extends Component {

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

    //  extrait la liste de noeuds depuis le formulaire
    //  ressemble à un array mais n'en a pas les méthodes
    const { pet } = this.form;

    // un lot de radios qui contient la valeur
    // vérifier dans le log de la console
    console.log(pet, pet.value);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <label>
            Cat
            <input type="radio" value="cat" name="pet" />
          </label>
          <label>
            Dog
            <input type="radio" value="dog" name="pet" />
          </label>
          <label>
            Ferret
            <input type="radio" value="ferret" name="pet" />
          </label>
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default RefsForm;

Ceci marche même si vous composez un formulaire depuis un composant enfant. Bien qu’il y ait plus de logique dans les composants, la technique pour récupérer la valeur depuis un lot de radios reste la même.

import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();

    //  extract the node list from the form
    //  it looks like an array, but lacks array methods
    const { pet } = this.form;

    // a set of radios has value property
    // checkout out the log for proof
    console.log(pet, pet.value);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <RadioSet
            setName={'pet'}
            setOptions={['cat', 'dog', 'ferret']} />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

function RadioSet(props) {
  return (
    <div>
      {props.setOptions.map(option => {
        return (
          <label
            key={option}
            style={{textTransform: 'capitalize'}}>
            {option}
            <input
              type="radio"
              value={option}
              name={props.setName} />
          </label>
        )
      })}
    </div>
  );
}

export default RefsForm;

4. Les Checkboxs

Contrairement à un lot de radios, un lot de checkbox peut avoir plusieurs valeurs sélectionnées. Ceci fait qu’il est un peu plus difficile d’en extraire les valeurs.

Récupérer les valeurs d’un lot de checkboxs sélectionnées peut être accompli à travers ces cinq étapes:

    1. Attribuer un ref à l’élément <form> (ligne 27 ci-dessous).
    2. Extraire le lot de checkboxs depuis le formulaire. Dans ce cas, c’est le ‘lot’ pet (ligne 9).
      • Içi, une liste de noeuds et une valeur sont retournés.
      • Gardez encore une fois à l’esprit que la liste de noeud ressemble à un array, mais n’en est pas un, et ne possède donc pas les méthodes propre à ces derniers, ce qui nous amène à l’étape suivante…
    3. Convertir la liste de noeuds en array, ce qui met leurs méthodes à notre disposition (checkboxArray à la ligne 12).
    4. Utiliser Array.filter() pour récupérer uniquement les checkbox cochées (checkedCheckboxes à la ligne 15).
    5. Utiliser Array.map() pour garder uniquement les valeurs des checkboxs cochées (checkedCheckboxesValues à la ligne 19).
import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();

    //  extract the node list from the form
    //  it looks like an array, but lacks array methods
    const { pet } = this.form;

    // convert node list to an array
    const checkboxArray = Array.prototype.slice.call(pet);

    // extract only the checked checkboxes
    const checkedCheckboxes = checkboxArray.filter(input => input.checked);
    console.log('checked array:', checkedCheckboxes);

    // use .map() to extract the value from each checked checkbox
    const checkedCheckboxesValues = checkedCheckboxes.map(input => input.value);
    console.log('checked array values:', checkedCheckboxesValues);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <label>
            Cat
            <input type="checkbox" value="cat" name="pet" />
          </label>
          <label>
            Dog
            <input type="checkbox" value="dog" name="pet" />
          </label>
          <label>
            Ferret
            <input type="checkbox" value="ferret" name="pet" />
          </label>
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

export default RefsForm;

Utiliser un composant enfant de lot de checkbox fonctionne exactement comme dans l’exemple des radios de la section précédente.

import React, { Component } from 'react';

class RefsForm extends Component {
  handleSubmit = (e) => {
    e.preventDefault();

    //  extract the node list from the form
    //  it looks like an array, but lacks array methods
    const { pet } = this.form;

    // convert node list to an array
    const checkboxArray = Array.prototype.slice.call(pet);

    // extract only the checked checkboxes
    const checkedCheckboxes = checkboxArray.filter(input => input.checked);
    console.log('checked array:', checkedCheckboxes);

    // use .map() to extract the value from each checked checkbox
    const checkedCheckboxesValues = checkedCheckboxes.map(input => input.value);
    console.log('checked array values:', checkedCheckboxesValues);
  }

  render() {
    return (
      <div>
        <form
          onSubmit={this.handleSubmit}
          ref={form => this.form = form}>
          <CheckboxSet
            setName={'pet'}
            setOptions={['cat', 'dog', 'ferret']} />
          <input type="submit" value="Submit" />
        </form>
      </div>
    );
  }
}

function CheckboxSet(props) {
  return (
    <div>
      {props.setOptions.map(option => {
        return (
          <label
            key={option}
            style={{textTransform: 'capitalize'}}>
            {option}
            <input
              type="checkbox"
              value={option}
              name={props.setName} />
          </label>
        )
      })}
    </div>
  );
}

export default RefsForm;

Conclusion

Si vous n’avez pas besoin de:

  1. surveiller la valeur de l’élément form en temps réel (exemple: pour afficher des composant en fonction de l’interaction de l’utilisateur), ou
  2. appliquer une vérification personnalisé des ‘input’ en temps réel,

alors utiliser refs pour récupérer les données depuis les éléments d’un formulaire n’est pas la bonne direction.

L’interêt principal d’utiliser refs par rapport à un controlled component est que, dans la plupart des cas, vous écrirez moins de code. Le cas exceptionnel est celui des ‘lots’ de checkboxs (et de radios dans une moindre mesure). Pour les groupes de checkbox, la quantité de code que vous gagnez en utilisant les refs est minimale, il est donc moins évident de savoir dans quels cas utiliser un controlled component plutôt que les refs.


React Forms: Using Refs est un billet traduit depuis CSS-Tricks

Laisser un commentaire

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