การแก้ไขสเตทของคอมโพเนนต์แม่ในคอมโพเนนต์ลูกใน 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>;
}

แม้ว่าเรายังไม่มี implementation ของ 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>;
}

ตอนนี้เรามาทำให้ในโหมด แก้ไข เรามีอินพุตพร้อมข้อมูล, และในโหมดปกติ - เป็นสแปน:

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 ที่คุณสร้างขึ้น ในบทเรียนก่อนหน้า