เปิดหัวข้อมาก็หาเรื่องซะแล้ว แต่หัวข้อเต็มๆของมันก็คือ Non Parent-Child Communication หมายถึง component 2 ตัวคุยกันโดยทั้ง 2 component นี้ไม่ได้เป็น parent และ child กันเลยโดยคุยผ่าน Event Bus ซึ่ง Document ที่เขียนเรื่องนี้ก็แอบอยู่ในซอกหลืบซอกใจของ Document และเขียนสั้นกระชับซะเหลือเกิน ทำให้คนเข้าใจยากแบบผมต้องหา และ กว่าจะหาเจอก็ไล่ไปยันบทความของรัสเซียกันเลยทีเดียวฮ่าๆ

ขอเกริ่นก่อนว่าทำไมถึงต้องมี Event Bus ลองคิดดูว่าถ้าเกิดมี Component ที่อยู่คนละ component แยกกันแต่อยากให้กดปุ่มที่ component A และ ไป trigger ตัว Component B ให้ทำงานยกตัวอย่าง Layout แบบนี้

จากรูปจะแยกออกเป็น 4 component ถ้าเกิดใน Header มีปุ่มอยู่และเมื่อคลิกจะทำการสั่งให้ Footer ไป call API ตัวนึงเพื่อแสดงผลข้อมูลเราจะทำอย่างไร

โดยปกติแล้วเราจะทำการใช้ Actions ของ Vuex เพื่อไปเรียก API และ ให้ Footer อ่านข้อมูลจาก Vuex มาแสดงผลแต่ใน Application ขนาดเล็ก หรือ ฟังก์ชั่นไม่ได้ยุ่งยากก็ไม่ต้องลำบากเขียน Vuex ให้วุ่นวายเราสามารถสั่งให้ Footer เรียก API ด้วยตัวเองผ่าน Event Bus


ตัว Event Bus นั้นผมมองว่ามันเป็น Base on $emit วิธีการใช้งานมันเหมือนการ $emit ค่าจาก Component ลูก ไป parent มากมาดูวิธีการทำกันดีกว่า จาก Document ของ Vue.js เค้าเขียนมาแค่นี้ !!! แต่ก็ยังพอเข้าใจได้แต่มันยังไม่ชัด

var bus = new Vue()
// in component A's method
bus.$emit('id-selected', 1)
// in component B's created hook
bus.$on('id-selected', function (id) {
// ...
})

ให้เราทำการสร้าง Vue Instant ขึ้นมาและนำตัวแปรมา $emit(‘ชื่อ Event’, data)

ใน component B เราเอา Instant ตัวเดิมมา $on(‘ชื่อ Event’, function (data) {}) เพื่อรับ event และ data ที่ถูกส่งผ่านตัว Vue Instant มา

สำหรับใครที่เขียน ES2015 ขึ้นไปสามารถใช้การ import มาช่วยได้แบบนี้

แต่สำหรับโปรเจคใหญ่ๆแล้วการมา import Event Hub ทุก component ที่จะใช้งานก็ดูจะยุ่งยากเกินไปเราสามารถยัดตัว Vue Instant ใส่ Vue.js prototype เลยเพื่อที่จะใช้งานผ่าน this ของแต่ละ Component

คำเตือน

การใช้งาน Event Bus นี้ใช้สำหรับ Component ที่ไม่ได้เป็น แม่ และ ลูก(non parent/Child) กัน หรือ component ที่ซ้อนกันเป็นชั้นๆอยู่ควรใช้การ $emit แบบธรรมดา

ใครไม่อ่านจะเสียใจ

สำหรับการ listener event นั้นถ้า component นั้นถูก ลบ หรือ เลิกใช้งานเราควรยกเลิกด้วย off() ด้วยเพราะถ้าเราไม่ยกเลิกและมีการ Set ค่าใน data หรือ $emit event ต่างๆจะเกิด Error แบบเจ็บปวดแน่นอนเพราะผมเจอมาแล้ว 555+ และ วิธีการแก้ก็ง่ายแสนง่ายแบบนี้

// life cycle Hook 
beforeDestroy() {
  this.$eventHub.$off('updateData') // ถ้าใช้ Vue.prototype
  EventHub.$off('updateData') // ถ้าใช้ import
}

สำหรับการเลือกใช้ Vue.prototype หรือ import ไฟล์ นั้นก็ลองดูที่ขนาดโปรเจคว่าเราจำเป็นต้องใช้งานบ่อยมั้ยถ้าใช้หลายจุดหลายไฟล์ก็สามารถ Set Prototype ได้เลย

Reference

เกี่ยวกับผู้เขียน

Itthipat Thitsarak

สวัสดีครับผม อิทธิพัทธ์ (เป้) เป็น Freelance Web developer ชอบหาเทคนิคต่างๆที่ทำให้ชีวิต Programmer ง่ายขึ้นโดย Blog นี้จะ สอน Laravel, Vuejs, CSS, HTML 5 และอื่นๆ ที่เกี่ยวกับการทำเว็บไซต์

ขอบคุณทุกคนที่ติดตาม และอ่านบทความของผมครับ หากใครมีคำถามหรืออยากให้ผมเขียนเกี่ยวกับเรื่องอะไรเพิ่มเติม สามารถแสดงความคิดเห็นไว้ที่ใต้บทความ หรือส่งเรื่องเข้ามาที่ Email ได้เลยครับ หัวข้อไหนน่าสนใจ ผมจะหยิบมาเขียนบทความให้ได้อ่านกันเรื่อยๆครับ

Scroll to Top
Scroll to Top