Darbo režimai per vaikinių komponentų būsenas React

Tarkime, mūsų produktų masyvas dabar atrodo taip:

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

Išveskime šiuos produktus HTML lentelės pavidalu. Tuo pačiu padarykime taip, kad paspaudus bet kurį lentelės langelį, šiame langelyje atsirastų įvesties laukas redagavimui. Užduočiai išspręsti sukursime 3 komponentus.

Komponentas Products saugos būseną su produktais ir naudos komponentus Product produktų išvedimui. Komponentas Product savo ruožtu taip pat naudos komponentus ProductField tam tikro produkto lauko (pavadinimo, kainos, kategorijos) išvedimui.

Komponentas ProductField rodys arba lauko tekstą, arba įvesties lauką jo redagavimui. Tuo tarpu redagavimo režimas arba rodymas tebūnie reguliuojamas šio komponento būsenos.

Tai yra, mes nesaugosime režimo tėvinėje būsenoje. Ten tai būtų labai nepatogu, nes mums tektų nurodyti režimą kiekvienam produkto laukui, kas paverstų mūsų būseną į kažką panašaus:

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

Tačiau mes nedarysime tokios būsenos, o paliksime tą, kuri buvo. Tiesiog kiekvienas komponento ProductField atvejis naudodamasis savo būsena reguliuos režimą: arba redagavimą, arba rodymą.

Taip išeis, kad tėvinis komponentas saugos būseną su duomenimis, o mūsų anūkinis komponentas gaus šiuos duomenis per propsus ir tuo pačiu turės savo būseną savo režimui keisti.

Taigi, įgyvendinkime aprašytą.

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

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

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

Praktinės užduotys

Задание 1

Atlikite analogiškus veiksmus su komponentais Users ir User, kuriuos sukūrėte ankstesnėse pamokose.