การแก้ไขสเตทของคอมโพเนนต์แม่ในคอมโพเนนต์ลูกใน React
ตอนนี้เรามาเริ่มแก้ไขผลิตภัณฑ์ของเรา โดยใช้อินพุตกัน สำหรับสิ่งนี้ในคอมโพเนนต์ลูก เราจะสร้างปุ่ม
เมื่อกดปุ่มนี้ครั้งแรก ให้แทนที่ ชื่อและราคาของผลิตภัณฑ์ด้วยอินพุต สำหรับการแก้ไข และเมื่อกดครั้งที่สอง ให้เปลี่ยนจากอินพุตกลับไปเป็นข้อความเหมือนเดิม
เราจะทำการเปลี่ยนแปลงในอาร์เรย์ของผลิตภัณฑ์ โดยเพิ่ม
คุณสมบัติ isEdit (และเพื่อความง่ายเราจะเอาการทำงานกับตะกร้าออก):
const 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
มาสร้างปุ่มสำหรับการแก้ไขในผลิตภัณฑ์:
function Product({ id, name, cost, isEdit }) {
return <div>
name: <span>{name}</span>
cost: <span>{cost}</span>
<button>edit</button>
</div>;
}
มาทำให้เมื่อคลิกที่ปุ่มนี้
จะเรียกใช้ฟังก์ชัน toggleMode บางส่วน,
ที่ส่งมาจากคอมโพเนนต์แม่:
function 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
ของผลิตภัณฑ์เป็นค่าตรงข้าม
เรายังจะทำให้ข้อความบนปุ่มเปลี่ยน ทุกครั้งที่กด:
function 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>;
}
ตอนนี้เรามาทำให้ในโหมด แก้ไข เรามีอินพุตพร้อมข้อมูล, และในโหมดปกติ - เป็นสแปน:
function 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:
function 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 ในนั้น:
function toggleMode(id) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod.isEdit = !prod.isEdit;
}
return prod;
}));
}
และสร้างฟังก์ชัน editProd ในนั้น:
function editProd(id, field, event) {
setProds(prods.map(prod => {
if (prod.id === id) {
prod[field] = event.target.value;
}
return prod;
}));
}
ในแท็กของผลิตภัณฑ์ เราจะส่งผ่าน
ฟังก์ชัน toggleMode และ editProd ของเราเป็นแอตทริบิวต์:
const 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
จะเป็นดังนี้:
function 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>;
}
โจทย์ฝึกปฏิบัติ
ให้ทำขั้นตอนเดียวกันกับคอมโพเนนต์
Users และ User ที่คุณสร้างขึ้น
ในบทเรียนก่อนหน้า