Tilatietojen käsittely Reactin lapsikomponenteissa

Oletetaan, että tuotetaulukkomme näyttää nyt seuraavalta:

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

Esitetään nämä tuotteet HTML-taulukkona. Tehdään myös niin, että minkä tahansa taulukon solun klikkaaminen näyttää syötekentän muokkausta varten. Ratkaistaksemme tehtävän luomme 3 komponenttia.

Komponentti Products säilyttää tilan tuotteilla ja käyttää Product komponentteja tuotteiden näyttämiseen. Komponentti Product puolestaan käyttää ProductField komponentteja näyttämään tietyn tuotteen kentän (nimi, hinta, kategoria).

Komponentti ProductField näyttää joko kentän tekstin tai syötekentän sen muokkaamista varten. Olkoon myös muokkaustila tai näyttötila säädeltynä tämän komponentin tilan avulla.

Eli emme tallenna tilaa ylemmässä tasossa. Siellä se olisi erittäin hankalaa, koska meidän pitäisi määrittää tila jokaiselle tuotteen kentälle, mikä muuttaisi tilamme joksikin tällaiseksi:

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

Emme kuitenkaan tee sellaista tilaa, vaan jätämme sen, joka oli. Yksinkertaisesti jokainen ProductField komponentin ilmentymä omassa tilassaan säätelee tilaa: joko muokkaus tai näyttö.

Siten käy niin, että ylemmän tason komponentti säilyttää tilan tiedoilla, ja meidän lapsenlapsikomponenttimme saa nämä tiedot propsien kautta ja sillä on samalla oma tilansa oman tilansa muuttamiseksi.

Joten, toteutetaan kuvattu.

Products-komponentti

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

Product-komponentti

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

ProductField-komponentti

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

Käytännön tehtävät

Задание 1

Suorita samanlaiset toimenpiteet Users ja User komponenttien kanssa, jotka loit aiemmissa oppitunneissa.