ואם בכל זאת אני רוצה להעביר משתנה ריאקטיבי ב Vue לילדים?
הקוד הבא ב Vue לא עובד, או לפחות לא עושה את מה שהתכוונתי. קומפוננטה עליונה:
<script setup>
import { ref } from 'vue'
import Child from './Child.vue';
const x = ref(10)
</script>
<template>
<Child :x="x" />
</template>
וקומפוננטת Child:
<script setup lang="ts">
const {x} = defineProps<{x: any}>();
function inc() {
x.value++;
}
</script>
<template>
<p>x = {{x}}</p>
<button @click="inc">+1</button>
</template>
נראה כאילו Child מקבל אוביקט ריאקטיבי x ומעלה את ערכו ב-1. בפועל העברת הפרמטר דרך props מעבירה את ה value של האוביקט הריאקטיבי, כלומר בתוך Child המשתנה x הוא מספר. למספר אין שדה .value
ולכן הקוד נכשל.
1. מה בכל זאת אפשר לעשות?
ל Vue יש שני פיתרונות טובים למצב הזה: הראשון הוא ש Child ידווח על אירוע ו Parent יטפל באירוע וישנה את x, והשני זה מקרו בשם defineModel
שבגדול מטפל בדינמיקה הזאת בשבילנו אבל מבחינת הקוד נראה לגמרי כמו העברת משתנה ריאקטיבי לקומפוננטה. שניהם פיתרונות טובים.
הפיתרון ש Vue לא רצו שניישם הוא לעטוף את המשתנה הריאקטיבי באוביקט. מוזר אבל עובד:
<script setup>
import { ref } from 'vue'
import Child from './Child.vue';
const x = ref({value: 10})
</script>
<template>
<Child :x="x" />
</template>
<script setup lang="ts">
const {x} = defineProps<{x: any}>();
function inc() {
x.value++;
}
</script>
<template>
<p>x = {{x.value}}</p>
<button @click="inc">+1</button>
</template>
ברור למה זה עובד - ref הוא רקורסיבי ולכן גם value שלו יהיה משתנה ריאקטיבי, אבל כשמעבירים אוביקט דרך props ויו לא מבטל את הריאקטיביות של השדות הפנימיים בצורה רקורסיבית ולכן Child יכול לשנות את המידע.
מה שלדעתי מעניין בדוגמה הזאת הוא כמה קל "לפתור" את הבעיה בצורה לא נכונה אולי אפילו בלי לשים לב שזה פיתרון לא נכון. שתי הדרכים ה"נכונות" לפיתרון דורשות היכרות עם מנגנונים נוספים של vue, ודווקא הפיתרון העקום הוא בעצם הפשוט ביותר, מהבחינה שהוא לא דורש עוד מנגנונים.
הלקח שלי מהדוגמה הזאת הוא שרק בגלל שפיתרון מסוים הוא היחיד שאני רואה זה עדיין לא אומר שזה הפיתרון הנכון. בשביל להגיע לפיתרון הנכון צריך לפעמים להמשיך לקרוא בתיעוד, להתלבט בין כמה אפשרויות ולהבין את היתרונות והחסרונות של כל אפשרות.