Werkmodi via staten van onderliggende componenten in React

Laten we aannemen dat onze array met producten er nu als volgt uitziet:

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

Laten we deze producten weergeven als een HTML tabel. Laten we het zo maken dat wanneer er op een willekeurige cel in de tabel wordt geklikt, er een invoerveld verschijnt in die cel voor bewerking. Om de taak op te lossen maken we 3 componenten.

De component Products zal de staat met producten opslaan en componenten Product gebruiken om producten weer te geven. De component Product zal op zijn beurt ook componenten ProductField gebruiken om een specifiek veld van het product weer te geven (naam, prijs, categorie).

De component ProductField zal ofwel de tekst van het veld tonen, of een invoerveld voor het bewerken ervan. Laat de bewerkingsmodus of weergavemodus worden geregeld door de staat van deze component.

Dat betekent dat we de modus niet zullen opslaan in de bovenliggende staat. Dat zou daar erg onhandig zijn, omdat we de modus voor elk veld van het product zouden moeten opgeven, wat onze staat zou veranderen in zoiets als:

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

We zullen echter zo'n staat niet maken, maar de originele behouden. Elk exemplaar van de component ProductField zal met behulp van zijn eigen staat de modus regelen: ofwel bewerken, ofwel weergeven.

Zo zal het blijken dat de bovenliggende component de staat met gegevens zal opslaan, terwijl onze onderliggende component deze gegevens via props ontvangt en tegelijkertijd zijn eigen staat zal hebben om zijn modus te wijzigen.

Laten we dus het beschrevene implementeren.

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

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

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

Praktische taken

Задание 1

Voer vergelijkbare bewerkingen uit met de componenten Users en User, die je hebt gemaakt in eerdere lessen.