Уредување на состојбата на родителот во детскиот компонент во React

Сега ајде да ги уредуваме нашите производи користејќи полиња за внесување. За ова, во детскиот компонент ќе направиме копче.

При првото кликнување на ова копче, наместо името и цената на производот, нека се појават полиња за внесување за нивно уредување, а при второто кликнување наместо полињата за внесување, нека се појават повторно текстовите.

Ќе направиме промена во низата со производи, додавајќи својство isEdit (а работата со кошничката за едноставност ќе ја отстраниме):

jsxconst initProds = [
  {id: id(), name: 'product1', cost: 100, isEdit: false},
  {id: id(), name: 'product2', cost: 200, isEdit: false},
  {id: id(), name: 'product3', cost: 300, isEdit: false},
];

Компонента Product

Да направиме копче за уредување во производот:

jsxfunction Product({ id, name, cost, isEdit }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    <button>edit</button>
  </div>;
}

Да направиме така што при клик на ова копче да се повика некоја функција toggleMode, пренесена од родителската компонента:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    
    <button onClick={() => toggleMode(id)}>
      edit
    </button>
  </div>;
}

Засега немаме имплементација за toggleMode, но знаеме дека таа ќе се наоѓа во родителската компонента, како параметар ќе прима id на производот и ќе го менува својството isEdit на производот на спротивно.

Да направиме и така што текстот на копчето да се менува при секое кликнување:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    name: <span>{name}</span>
    cost: <span>{cost}</span>
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'save': 'edit'}
    </button>
  </div>;
}

Сега да направиме така што во режимот на уредување да имаме полиња за внесување со податоците, а во обичниот режим - елементи span:

jsxfunction Product({ id, name, cost, isEdit, toggleMode }) {
  return <div>
    name: {isEdit ? <input value={name} /> : <span>{name}</span>}
    cost: {isEdit ? <input value={cost} /> : <span>{cost}</span>}
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'save': 'edit'}
    </button>
  </div>;
}

Да ги поврземе нашите полиња за внесување со настанот onChange, во кој ќе ја повикуваме некоја родителска функција editProd:

jsxfunction Product({ id, name, cost, isEdit, toggleMode, editProd }) {
  return <div>
    name: {
      isEdit
      ? <input value={name} onChange={event => editProd(id, 'name', event)} />
      : <span>{ name }</span>
    }
    cost: {
      isEdit
      ? <input value={cost} onChange={event => editProd(id, 'cost', event)} />
      : <span>{ cost }</span>
    }
    
    <button onClick={() => toggleMode(id)}>
      {isEdit ? 'save': 'edit'}
    </button>
  </div>;
}

Компонента Products

Сега да преминеме во компонентата Products. Да ја имплементираме во неа функцијата toggleMode:

jsxfunction toggleMode(id) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod.isEdit = !prod.isEdit;
    }
    
    return prod;
  }));
}

Исто така, да ја имплементираме во неа функцијата editProd:

jsxfunction editProd(id, field, event) {
  setProds(prods.map(prod => {
    if (prod.id === id) {
      prod[field] = event.target.value;
    }
    
    return prod;
  }));
}

Во тегот со производот како атрибути ќе ги пренесеме нашите функции toggleMode и editProd:

jsxconst items = prods.map(prod => {
  return <Product
    key ={prod.id}
    id  ={prod.id}
    name={prod.name}
    cost={prod.cost}
    isEdit={prod.isEdit}
    toggleMode={toggleMode}
    editProd={editProd}
  />;
});

Конечниот код на компонентата Products ќе изгледа вака:

jsxfunction Products() {
  const [prods, setProds] = useState(initProds);
  
  function toggleMode(id) {
    setProds(prods.map(prod => {
      if (prod.id === id) {
        prod.isEdit = !prod.isEdit;
      }
      
      return prod;
    }));
  }
  
  function editProd(id, field, event) {
    setProds(prods.map(prod => {
      if (prod.id === id) {
        prod[field] = event.target.value;
      }
      
      return prod;
    }));
  }
  
  const result = prods.map(prod => {
    return <Product
      key ={prod.id}
      id  ={prod.id}
      name={prod.name}
      cost={prod.cost}
      isEdit={prod.isEdit}
      toggleMode={toggleMode}
      editProd={editProd}
    />;
  });
  
  return <div>
    {result}
  </div>;
}

Практични задачи

Задание 1

Направете слични операции со компонентите Users и User, креирани од вас во претходните лекции.