ลองนึกภาพการเพิ่มตัวนับในองค์ประกอบบางส่วน:
class SomeComponent extends Component{
state = {
updatedByDiv: '',
updatedByBtn: '',
counter: 0
}
divCountHandler = () => {
this.setState({
updatedByDiv: 'Div',
counter: this.state.counter + 1
});
console.log('divCountHandler executed');
}
btnCountHandler = () => {
this.setState({
updatedByBtn: 'Button',
counter: this.state.counter + 1
});
console.log('btnCountHandler executed');
}
...
...
render(){
return (
...
// a parent div
<div onClick={this.divCountHandler}>
// a child button
<button onClick={this.btnCountHandler}>Increment Count</button>
</div>
...
)
}
}
มีตัวจัดการการนับติดอยู่กับทั้งส่วนประกอบหลักและส่วนประกอบย่อย สิ่งนี้ทำโดยเจตนาเพื่อให้เราสามารถเรียกใช้ setState () สองครั้งภายในบริบทฟองเหตุการณ์คลิกเดียวกัน แต่จากภายใน 2 ตัวจัดการที่แตกต่างกัน
อย่างที่เราคิดว่าเหตุการณ์การคลิกเพียงครั้งเดียวบนปุ่มจะทริกเกอร์ตัวจัดการทั้งสองนี้เนื่องจากเหตุการณ์ฟองอากาศจากเป้าหมายไปยังคอนเทนเนอร์ด้านนอกสุดในช่วงฟองสบู่
ดังนั้น btnCountHandler () จึงดำเนินการก่อนโดยคาดว่าจะเพิ่มจำนวนเป็น 1 จากนั้น divCountHandler () จะดำเนินการคาดว่าจะเพิ่มจำนวนเป็น 2
อย่างไรก็ตามจะนับเพิ่มทีละ 1 เท่านั้นตามที่คุณตรวจสอบได้ในเครื่องมือ React Developer
สิ่งนี้พิสูจน์ได้ว่ามีปฏิกิริยา
จัดคิวการเรียก setState ทั้งหมด
กลับมาที่คิวนี้หลังจากเรียกใช้เมธอดสุดท้ายในบริบท (divCountHandler ในกรณีนี้)
รวมการกลายพันธุ์ของอ็อบเจ็กต์ทั้งหมดที่เกิดขึ้นภายในการเรียก setState หลายรายการในบริบทเดียวกัน (การเรียกเมธอดทั้งหมดภายในเฟสเหตุการณ์เดียวเป็นบริบทเดียวกันสำหรับเช่น) เป็นไวยากรณ์การกลายพันธุ์ของอ็อบเจ็กต์เดียว (การรวมเข้ากันได้ดีเพราะนี่คือเหตุผลที่เราสามารถอัปเดตคุณสมบัติสถานะได้อย่างอิสระ ใน setState () ตั้งแต่แรก)
และส่งผ่านไปยัง setState () เดียวเพื่อป้องกันการแสดงผลซ้ำเนื่องจากการเรียกใช้ setState () หลายครั้ง (นี่เป็นคำอธิบายแบบดั้งเดิมของ batching)
โค้ดผลลัพธ์รันโดย react:
this.setState({
updatedByDiv: 'Div',
updatedByBtn: 'Button',
counter: this.state.counter + 1
})
หากต้องการหยุดพฤติกรรมนี้แทนที่จะส่งอ็อบเจ็กต์เป็นอาร์กิวเมนต์ไปยังเมธอด setState จะมีการส่งการเรียกกลับ
divCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByDiv: 'Div',
counter: prevState.counter + 1
};
});
console.log('divCountHandler executed');
}
btnCountHandler = () => {
this.setState((prevState, props) => {
return {
updatedByBtn: 'Button',
counter: prevState.counter + 1
};
});
console.log('btnCountHandler executed');
}
หลังจากเมธอดสุดท้ายเสร็จสิ้นการเรียกใช้งานและเมื่อ react กลับไปประมวลผลคิว setState ก็เพียงแค่เรียกการเรียกกลับสำหรับ setState แต่ละรายการที่อยู่ในคิวโดยส่งผ่านในสถานะส่วนประกอบก่อนหน้า
การตอบสนองด้วยวิธีนี้ช่วยให้มั่นใจได้ว่าการเรียกกลับครั้งสุดท้ายในคิวจะได้รับการอัปเดตสถานะที่คู่สัญญาก่อนหน้าทั้งหมดได้วางมือไว้