เนื้อหาตอนต่อไปนี้ เรามาดูพื้นฐานส่วนที่สำคัญอีกส่วนหนึ่ง นั่นก็คือ
เกี่ยวกับ Reactivity System และการกำหนดตัวแปร หรือใน vuejs
มักจะเรียกว่า Reactive State ซึ่งเราได้ผ่านตารูปแบบการใช้งานเบื้องต้น
มาแล้วบ้าง นั่นก็คือการกำหนดโดยใช้ฟังก์ชั่น ref()
เกี่ยวกับ Reactive State ใน vuejs
ใน Vue.js, Reactive State หมายถึงการที่ข้อมูลที่ถูกใช้ในแอพพลิเคชั่น Vue.js จะถูก
ติดตามการเปลี่ยนแปลงและอัพเดตอัตโนมัติเมื่อมีการเปลี่ยนแปลงข้อมูลนั้น ๆ โดยอัตโนมัติและ
อย่างรวดเร็ว การทำให้ข้อมูลเป็น Reactive เป็นสิ่งสำคัญที่ทำให้ Vue.js มีประสิทธิภาพและ
เป็นมาตรฐานสำหรับการพัฒนาแอพพลิเคชันที่ไหลไปมาของข้อมูลอย่างกระชับและเรียลไทม์
โดยไม่ต้องตรวจสอบเงื่อนไขเพื่ออัพเดตข้อมูลด้วยตนเอง
Vue.js ใช้กฏต่าง ๆ ในการตรวจจับการเปลี่ยนแปลงของข้อมูลและทำให้มันเป็น Reactive ดังนี้:
1.Object.defineProperty: Vue.js ใช้ Object.defineProperty เพื่อสร้าง Getters
และ Setters สำหรับคุณสมบัติของอ็อบเจกต์ ทำให้ Vue.js สามารถตรวจจับการเปลี่ยนแปลง
ของคุณสมบัติได้และอัพเดต View ตามความเปลี่ยนแปลงนั้น
2.Observer: Vue.js มีตัว Observer ที่สังเกตการเปลี่ยนแปลงของข้อมูลที่ถูกใช้ในโค้ด
Vue.js และแจ้งเตือน Vue.js เมื่อมีการเปลี่ยนแปลง
3.Reactivity System: Vue.js มีระบบ Reactivity ที่ประมวลผลและติดตามความ
เปลี่ยนแปลงของข้อมูลอัตโนมัติ ทำให้มันเป็นเหมือน Reactivity System ที่สามารถ
ติดตามและอัพเดตข้อมูลอัตโนมัติโดยไม่ต้องตรวจสอบเงื่อนไขโดยตรง
เมื่อข้อมูลถูกทำให้เป็น Reactive แล้ว การเปลี่ยนแปลงของข้อมูลที่ถูกใช้ในแอพพลิเคชั่น Vue.js
จะถูกตรวจจับอัตโนมัติ และอัพเดต View ในเวลาเดียวกันโดยไม่ต้องมีการสั่งให้มันอัพเดตโดยตรง
นี่คือเหตุผลที่ Vue.js เป็นเครื่องมือที่สามารถพัฒนาแอพพลิเคชั่นเรียลไทม์ได้อย่างมีประสิทธิภาพ
และง่ายต่อการบำรุงรักษาและจัดการ
การกำหนด Reactive State
รูปแบบการกำหนด reactive state เราน่าจะคุ้นมาบ้างแล้วจากตัวอย่างๆที่ผ่านมา
import { ref } from 'vue' const count = ref(0) const count = 0 // ถ้ากำหนดแบบไม่ใช้ฟังก์ชั่น ref() ตัวแปร count หากมีการเปลี่ยนแปลง // ก็จะไม่มีผลให้ DOM มีการ rendor หรืออัพเดท HTML ใหม่ ดึงนั้นจึงมีการใช้งาน ref()
ดูตัวอย่างไฟล์ App.vue นี้ประกอบการอธิบาย
<script setup> import { ref } from 'vue' const count = ref(0) function increment() { count.value++ } </script> <template> <button @click="increment"> {{ count }} </button> </template>
ส่วน <script setup> คือเทคนิคใหม่ใน Vue 3 ที่ช่วยให้เราสร้างคอมโพเนนต์ได้อย่างสั้นและ
กระชับมากขึ้น โดยทำการเขียนโค้ด JavaScript และประกาศความสัมพันธ์ของตัวแปรทั้งหมด
ในส่วนนี้
1.<script setup>: เริ่มต้นด้วยบล็อก <script setup> ซึ่งใช้เพื่อระบุว่าเราจะเขียนโค้ด
JavaScript สำหรับคอมโพเนนต์นี้ โดย Vue 3 จะทำการจัดการการสร้าง Reactivity
และประกาศตัวแปรให้เราอัตโนมัติ
2.import { ref } from 'vue': เรียกใช้งาน ref จาก Vue เพื่อสร้าง reactive reference
ใน JavaScript
3.const count = ref(0): ประกาศตัวแปร count โดยใช้ ref() เพื่อสร้าง reactive reference
ที่มีค่าเริ่มต้นเป็น 0
4.function increment(): ประกาศฟังก์ชัน increment() ซึ่งจะเพิ่มค่าของ count ทีละหนึ่งทุก
ครั้งที่ถูกเรียกใช้
ส่วน <template> เป็นส่วนที่ใช้สำหรับเขียน HTML Template ของคอมโพเนนต์
5.<button @click="increment">: สร้างปุ่มที่เมื่อคลิกจะเรียกใช้ฟังก์ชัน increment()
6.{{ count }}: แสดงค่าของตัวแปร count ภายในปุ่ม โดย Vue 3 จะทำการทำ reactive
binding โดยอัตโนมัติ ซึ่งหมายความว่าข้อมูลจะถูกอัพเดตอัตโนมัติเมื่อมีการเปลี่ยนแปลง
ทำให้ข้อมูลที่แสดงผลบนหน้าเว็บถูกอัพเดตอัตโนมัติและโชว์ผลลัพธ์ล่าสุดทุกครั้งที่มีการเปลี่ยนแปลง
การใช้ฟังก์ชั่น ref() จะทำให้ได้ object ที่มี value property ดังรูปตัวอย่าง
หากต้องการเปลี่ยนแปลงค่าในส่วนของ script เราต้องกำหนดค่าผ่าน value property
ตัวอย่างเช่น การเพิ่มค่า ก็จะใช้เป็น count.value++
แต่เวลาเรานำไปใช้งานเพื่อแสดงข้อมูลใน template จะไม่ต้องกำหนด .value นั่นคือ
ไม่ต้องกำหนดเป็น {{ count.value }} แต่ใช้เป็น {{ count }} แทนได้เลย
การกำหนดค่า Reactive State ด้วย ref()
เราสามารถกำหนดชนิดข้อมูลใดๆ ก็ได้ด้วยฟังก์ชั่น ref() รวมถึงอ็อบเจกต์ที่มีโครงสร้างที่ซับซ้อน
และมีการซ้อนกันของคุณสมบัติภายในอีกเป็นบรรทัดๆ รวมถึงพวก array หรือ Map ที่เป็นรูป
แบบโครงสร้างข้อมูลของ JavaScript ดูตัวอย่างโครงสร้างข้อมูลที่ซับซ้อนด้านล่างประกอบ
import { ref } from 'vue' const obj = ref({ nested: { count: 0 }, arr: ['foo', 'bar'] }) function mutateDeeply() { obj.value.nested.count++ obj.value.arr.push('baz') }
คำอธิบายการทำงาน
1.const obj = ref({ nested: { count: 0 }, arr: ['foo', 'bar'] }): สร้าง reactive
reference ชื่อ obj ที่มีค่าเริ่มต้นเป็น object ที่ประกอบด้วย property ชื่อ nested
ที่มี property count และ property ชื่อ arr ที่มีค่าเริ่มต้นเป็น array ['foo', 'bar']
2.function mutateDeeply() { ... }: ประกาศฟังก์ชัน mutateDeeply() ซึ่งมีการเข้าถึง
และเปลี่ยนแปลงข้อมูลภายใน obj โดยการเพิ่มค่าใน count ของ nested และเพิ่มค่าใหม่
ลงใน arr
3.obj.value.nested.count++: เข้าถึงค่า nested ใน obj และเพิ่มค่า count อีกหนึ่ง
เมื่อ mutateDeeply() ถูกเรียก
4.obj.value.arr.push('baz'): เข้าถึง array arr ใน obj และเพิ่มค่า 'baz' เข้าไปใน array
นั้นเมื่อ mutateDeeply() ถูกเรียก
การใช้งานฟังก์ชัน reactive() เพื่อกำหนด Reactive State
นอกจากการใช้งานฟังก์ชั่น ref() ก็ยังไมีฟังก์ชั่น reactive() ที่ใช้สำหรับกำหนด State ซึ่ง
ความแต่งของทั้งสองวิธีเป็นดังนี้
ref():
1.ref() ใช้สำหรับสร้าง reactive reference หรือ reference ที่เป็น reactive
ในรูปแบบของค่าเดียว (primitive value) เช่น number, string, boolean,
หรือ object หนึ่งตัว
2.เมื่อใช้ ref() เราต้องเข้าถึงค่าใน reference ด้วย .value เพื่อทำการอ่านหรือ
เปลี่ยนแปลงค่า
3.เหมาะสำหรับใช้กับค่าที่เปลี่ยนแปลงบ่อยและต้องการ reactivity อย่างง่าย
reactive():
1.reactive() ใช้สำหรับสร้าง reactive objects ซึ่งเป็น reactive ทั้งหมด
คือทุก property ภายใน object นั้นเป็น reactive ไม่ว่าจะเป็น primitive value
หรือ object อื่น ๆ
2.เมื่อใช้ reactive() เราไม่จำเป็นต้องใช้ .value เพื่อเข้าถึงค่า แต่สามารถเข้าถึงค่าได้โดยตรง
3.เหมาะสำหรับใช้กับ object ที่มีโครงสร้างที่ซับซ้อนและต้องการ reactivity ในทุก
property ของ object นั้น
ตัวอย่างการกำหนด state ด้วยฟังก์ชั่น reactive()
<script setup> import { reactive } from 'vue' const state = reactive({ count: 0 }) console.log(state) function increment() { state.count++ } </script> <template> <button @click="increment"> {{ state.count }} </button> </template>
สังเกตว่าเมื่อเราใช้งานฟังก์ชั่น reactive() ก็จะสามารถอ้างอิงค่าตัวแปรโดยไม่ต้องผ่าน
.value property เนื่องจากจะไม่มีค่านี้ และ reactive object ที่ถูกสร้างขึ้นก็จะเป็น
ในรูปแบบของ JavaScript Proxies ที่ทำงานเหมือน object ปกติทั่วไป
อย่างไรก็ดีฟังก์ชั่นนี้ก็มีข้อจำกัด เช่น ไม่สามารถใช้กำหนดชนิดข้อมูลพื้นฐานได้ เช่น ตัวเลข
ข้อความ ค่า boolean และตัวแปรพื้นฐานอื่นๆ ที่ไม่สามารถแยกต่อได้ โดยฟังก์ชั่นนี้จะ
เหมาะกับตัวแปร object, arrays, Map และ Set ที่มีความซับซ้อนมากกว่า ข้อจำกัดต่อมา
ก็คือไม่สามารถแทนค่าอ้อปเจกต์ทั้งหมดด้วยค่าใหม่ทีเดียวได้ และสุดท้ายคือเมื่อทำการ
destructuring หรือการแยกค่าจาก object หรือ array เป็นตัวแปรทีละชิ้น จะไม่สะดวกใน
การใช้งาน เพราะโค้ดมีโครงสร้างที่ซับซ้อนหรือไม่เข้ากันได้กับการใช้งาน destructuring
อย่างไม่สมบูรณ์ ตัวอย่างเช่น
const state = reactive({ count: 0 }) // เมื่อมีการ destructuring ตัวแปร count จะหลุดการเชื่อมต่อกับ // state.count หรือก็คือตัวแปร count ไม่มีผลกับการเปลี่ยนแปลงค่า state let { count } = state // ไม่มีผลกับการเปลี่ยนแปลงค่า state count++ // หรือกรณีนำเข้าไปในฟังก์ชั่น ก็จะไม่มีผลกับการเปลี่ยนแปลงของ state callSomeFunction(state.count)
ด้วยข้อจำกัดดังกล่าวข้างต้น ดังนั้นจึงแนะนำให้ใช้ฟังก์ชั่น ref() เป็นฟังก์ชั่นหลักในการ
กำหนดตัวแปรสำหรับ reactive state