Modes de fonctionnement via les états des composants enfants dans React

Supposons que notre tableau de produits ressemble maintenant à ceci :

jsxconst initProds = [
  {id: id(), name: 'prod1', cost: 'cost1', catg: 'catg1'},
  {id: id(), name: 'prod2', cost: 'cost2', catg: 'catg2'},
  {id: id(), name: 'prod3', cost: 'cost3', catg: 'catg3'},
];

Affichons ces produits sous forme de tableau HTML. Faisons en sorte qu'un clic sur n'importe quelle cellule du tableau fasse apparaître un champ de saisie pour la modifier. Pour résoudre cette tâche, nous créerons 3 composants.

Le composant Products stockera l'état des produits et utilisera les composants Product pour afficher les produits. Le composant Product utilisera à son tour les composants ProductField pour afficher un champ spécifique du produit (nom, prix, catégorie).

Le composant ProductField affichera soit le texte du champ, soit un champ de saisie pour le modifier. Le mode édition ou affichage sera régulé par l'état de ce composant.

C'est-à-dire que nous ne stockerons pas le mode dans l'état du parent. Cela serait très peu pratique ici, car nous devrions spécifier le mode pour chaque champ de produit, ce qui transformerait notre état en quelque chose comme ceci :

jsxconst initProds = [
  [
    {field: 'name', value: 'prod1', isEdit: false},
    {field: 'cost', value: 'cost1', isEdit: false},
    {field: 'catg', value: 'catg1', isEdit: false},
  ],
  [
    {field: 'name', value: 'prod2', isEdit: false},
    {field: 'cost', value: 'cost2', isEdit: false},
    {field: 'catg', value: 'catg2', isEdit: false},
  ],
  [
    {field: 'name', value: 'prod3', isEdit: false},
    {field: 'cost', value: 'cost3', isEdit: false},
    {field: 'catg', value: 'catg3', isEdit: false},
  ],
]

Cependant, nous ne créerons pas un tel état, et garderons celui qui existait. Simplement, chaque instance du composant ProductField régulera son mode via son propre état : soit l'édition, soit l'affichage.

Ainsi, le composant parent stockera l'état avec les données, et notre composant petit-enfant recevra ces données via les props tout en ayant son propre état pour changer son mode.

Maintenant, implémentons ce qui a été décrit.

Composant Products

jsxfunction Products() {
  const [prods, setProds] = useState(initProds);
  
  function changeField(id, field, event) {
    setProds(prods.map(prod => {
      if (prod.id === id) {
        prod[field] = event.target.value;
      }
      
      return prod;
    }));
  }
  
  const rows = prods.map(prod => {
    return <Product
      key ={prod.id}
      id  ={prod.id}
      name={prod.name}
      cost={prod.cost}
      catg={prod.catg}
      changeField={changeField}
    />;
  });
  
  return <div>
    <table>
      <tbody>
        {rows}
      </tbody>
    </table>
  </div>;
}

Composant Product

jsxfunction Product({ id, name, cost, catg, changeField }) {
  return <tr>
    <ProductField id={id} text={name} type="name" changeField={changeField} />
    <ProductField id={id} text={cost} type="cost" changeField={changeField} />
    <ProductField id={id} text={catg} type="catg" changeField={changeField} />
  </tr>;
}

Composant ProductField

jsxfunction ProductField({ id, text, type, changeField }) {
  const [isEdit, setIsEdit] = useState(false);
  
  return <td>
    {
      isEdit
      ? <input
        value={text}
        onChange={event => changeField(id, type, event)}
        onBlur={() => setIsEdit(false)}
      />
      : <span onClick={() => setIsEdit(true)}>{text}</span>
    }
  </td>;
}

Tâches pratiques

Задание 1

Répétez des opérations similaires avec les composants Users et User que vous avez créés dans les leçons précédentes.