التفاعلية في Vue

نشرت: 2022-03-10
ملخص سريع ↬ التفاعلية هي قدرة متغير (مصفوفة ، سلسلة ، رقم ، كائن ، إلخ) على التحديث عندما يتم تغيير قيمته أو أي متغير آخر يشير إليه بعد الإعلان.

في هذه المقالة ، سنلقي نظرة على التفاعلية في Vue ، وكيف تعمل ، وكيف يمكننا إنشاء متغيرات تفاعلية باستخدام طرق ووظائف تم إنشاؤها حديثًا. تستهدف هذه المقالة المطورين الذين لديهم فهم جيد لكيفية عمل Vue 2.x ويتطلعون إلى التعرف على Vue 3 الجديد.

سنقوم ببناء تطبيق بسيط لفهم هذا الموضوع بشكل أفضل. يمكن العثور على رمز هذا التطبيق على GitHub.

بشكل افتراضي ، جافا سكريبت ليست تفاعلية . هذا يعني أننا إذا أنشأنا المتغير boy وقمنا بالإشارة إليه في الجزء A من تطبيقنا ، ثم تابع تعديل boy في الجزء B ، فلن يتم تحديث الجزء A بالقيمة الجديدة لـ boy .

 let framework = 'Vue'; let sentence = `${framework} is awesome`; console.log(sentence) // logs "Vue is awesome" framework = 'React'; console.log(sentence) //should log "React is awesome" if 'sentence' is reactive.

المقتطف أعلاه هو مثال ممتاز للطبيعة غير التفاعلية لجافا سكريبت - وبالتالي ، لماذا لا ينعكس التغيير في متغير sentence .

في Vue props ، كانت العناصر الخاصة computed data() جميعها تفاعلية بشكل افتراضي ، باستثناء الخصائص التي لم تكن موجودة في data عند إنشاء هذه المكونات. هذا يعني أنه عند إدخال مكون في DOM ، فإن الخصائص الموجودة في كائن data المكون فقط هي التي ستؤدي إلى تحديث المكون إذا تغيرت هذه الخصائص ومتى تغيرت.

داخليًا ، يستخدم Vue 3 كائن Proxy (ميزة ECMAScript 6) للتأكد من أن هذه الخصائص تفاعلية ، لكنها لا تزال توفر خيار استخدام Object.defineProperty من Vue 2 لدعم Internet Explorer (ECMAScript 5). تحدد هذه الطريقة خاصية جديدة مباشرة على كائن ما ، أو تعدل خاصية موجودة على كائن ما ، وتقوم بإرجاع الكائن.

للوهلة الأولى وبما أن معظمنا يعرف بالفعل أن التفاعلية ليست جديدة في Vue ، فقد يبدو من غير الضروري الاستفادة من هذه الخصائص ، ولكن واجهة برمجة التطبيقات Options لها حدودها عندما تتعامل مع تطبيق كبير مع وظائف قابلة لإعادة الاستخدام في عدة أجزاء من التطبيق. تحقيقا لهذه الغاية ، تم تقديم Composition API الجديد للمساعدة في استخلاص المنطق من أجل تسهيل قراءة قاعدة التعليمات البرمجية وصيانتها. أيضًا ، يمكننا الآن بسهولة جعل أي متغير تفاعليًا بغض النظر عن نوع بياناته باستخدام أي من الخصائص والطرق الجديدة.

عندما نستخدم خيار setup ، الذي يعمل كنقطة دخول لـ Composition API ، يتعذر الوصول إلى كائن data والخصائص computed methods لأن مثيل المكون لم يتم إنشاؤه بعد عند تنفيذ setup . هذا يجعل من المستحيل الاستفادة من التفاعلية المضمنة في أي من هذه الميزات في setup . في هذا البرنامج التعليمي ، سوف نتعرف على كل الطرق التي يمكننا بها القيام بذلك.

المزيد بعد القفز! أكمل القراءة أدناه ↓

الطريقة التفاعلية

وفقًا للوثائق ، يمكن أن تكون الطريقة reactive ، التي تعادل Vue.observable() في Vue 2.6 ، مفيدة عندما نحاول إنشاء كائن تكون جميع خصائصه تفاعلية (مثل كائن data في الخيارات API). تحت الغطاء ، يستخدم كائن data في Options API هذه الطريقة لجعل جميع الخصائص الموجودة فيه تفاعلية.

لكن يمكننا إنشاء كائن تفاعلي خاص بنا مثل هذا:

 import { reactive } from 'vue' // reactive state let user = reactive({ "id": 1, "name": "Leanne Graham", "username": "Bret", "email": "[email protected]", "address": { "street": "Kulas Light", "suite": "Apt. 556", "city": "Gwenborough", "zipcode": "92998-3874", "geo": { "lat": "-37.3159", "lng": "81.1496" } }, "phone": "1-770-736-8031 x56442", "website": "hildegard.org", "company": { "name": "Romaguera-Crona", "catchPhrase": "Multi-layered client-server neural-net", "bs": "harness real-time e-markets" }, "cars": { "number": 0 } })

هنا ، قمنا باستيراد الطريقة reactive من Vue ، ثم أعلنا متغير user الخاص بنا عن طريق تمرير قيمته إلى هذه الوظيفة كوسيطة. عند القيام بذلك ، جعلنا user متفاعلًا ، وبالتالي ، إذا استخدمنا user في القالب الخاص بنا وإذا كان يجب تغيير الكائن أو خاصية هذا الكائن ، فسيتم تحديث هذه القيمة تلقائيًا في هذا القالب.

ref

مثلما لدينا طريقة لجعل الكائنات تفاعلية ، نحتاج أيضًا إلى واحدة لجعل القيم الأولية الأخرى المستقلة (سلاسل ، منطقية ، قيم غير محددة ، أرقام ، إلخ) والمصفوفات تفاعلية. أثناء التطوير ، سنعمل مع أنواع البيانات الأخرى هذه بينما نحتاج إليها أيضًا لتكون تفاعلية. النهج الأول الذي قد نفكر فيه هو استخدام reactive وتمرير قيمة المتغير الذي نريد جعله رد الفعل.

 import { reactive } from 'vue' const state = reactive({ users: [], });

نظرًا لأن reactive يحتوي على تحويل تفاعلي عميق ، سيكون user أيضًا كخاصية رد الفعل ، وبالتالي تحقيق هدفنا ؛ ومن ثم ، user دائمًا بالتحديث في أي مكان يتم استخدامه في نموذج هذا التطبيق. ولكن باستخدام خاصية ref ، يمكننا جعل أي متغير بأي نوع بيانات تفاعليًا عن طريق تمرير قيمة هذا المتغير إلى ref . تعمل هذه الطريقة أيضًا مع الكائنات ، ولكنها تتداخل مع الكائن بمستوى واحد أعمق مما كانت عليه عند استخدام الطريقة reactive .

 let property = { rooms: '4 rooms', garage: true, swimmingPool: false } let reactiveProperty = ref(property) console.log(reactiveProperty) // prints { // value: {rooms: "4 rooms", garage: true, swimmingPool: false} // }

تحت الغطاء ، يأخذ ref هذه الحجة التي تم تمريرها إليه ويحولها إلى كائن ذي مفتاح ذي value . هذا يعني أنه يمكننا الوصول إلى المتغير الخاص بنا عن طريق استدعاء variable.value Value ، ويمكننا أيضًا تعديل قيمته من خلال استدعائه بنفس الطريقة.

 import {ref} from 'vue' let age = ref(1) console.log(age.value) //prints 1 age.value++ console.log(age.value) //prints 2

باستخدام هذا ، يمكننا استيراد ref إلى مكوننا وإنشاء متغير تفاعلي:

 <template> <div class="home"> <form @click.prevent=""> <table> <tr> <th>Name</th> <th>Username</th> <th>email</th> <th>Edit Cars</th> <th>Cars</th> </tr> <tr v-for="user in users" :key="user.id"> <td>{{ user.name }}</td> <td>{{ user.username }}</td> <td>{{ user.email }}</td> <td> <input type="number" name="cars" v-model.number="user.cars.number" /> </td> <td> <cars-number :cars="user.cars" /> </td> </tr> </table> <p>Total number of cars: {{ getTotalCars }}</p> </form> </div> </template> <script> // @ is an alias to /src import carsNumber from "@/components/cars-number.vue"; import axios from "axios"; import { ref } from "vue"; export default { name: "Home", data() { return {}; }, setup() { let users = ref([]); const getUsers = async () => { let { data } = await axios({ url: "data.json", }); users.value = data; }; return { users, getUsers, }; }, components: { carsNumber, }, created() { this.getUsers(); }, computed: { getTotalCars() { let users = this.users; let totalCars = users.reduce(function(sum, elem) { return sum + elem.cars.number; }, 0); return totalCars; }, }; </script>

هنا ، قمنا باستيراد ref من أجل إنشاء متغير users تفاعلي في مكوننا. ثم استوردنا axios لجلب البيانات من ملف JSON في المجلد public ، carsNumber مكون carsNumber ، والذي سننشئه لاحقًا. الشيء التالي الذي قمنا به هو إنشاء متغير users تفاعلي باستخدام طريقة ref ، بحيث يمكن users التحديث متى تغيرت الاستجابة من ملف JSON الخاص بنا.

أنشأنا أيضًا دالة getUser التي تجلب مصفوفة users من ملف JSON باستخدام محاور ، وقمنا بتعيين القيمة من هذا الطلب إلى متغير users . أخيرًا ، أنشأنا خاصية محسوبة تحسب العدد الإجمالي للسيارات التي يمتلكها مستخدمونا كما عدلناها في قسم النموذج.

من المهم ملاحظة أنه عند الوصول إلى خصائص ref التي يتم إرجاعها في قسم القالب أو خارج setup() ، يتم تفكيكها تلقائيًا بشكل سطحي. هذا يعني أن refs التي هي كائن ستظل تتطلب .value . ليتم الوصول إليها. نظرًا لأن users عبارة عن مصفوفة ، يمكننا ببساطة استخدام users وليس users.value في getTotalCars .

في قسم النموذج ، قمنا بعرض جدول يعرض معلومات كل مستخدم ، جنبًا إلى جنب مع مكون <cars-number /> . يقبل هذا المكون خاصية cars التي يتم عرضها في صف كل مستخدم على أنها عدد السيارات التي يمتلكونها. يتم تحديث هذه القيمة كلما تغيرت قيمة cars في كائن المستخدم ، وهو بالضبط كيف سيعمل كائن data أو الخاصية computed إذا كنا نعمل مع Options API.

toRefs

عندما نستخدم Composition API ، تقبل وظيفة setup وسيطين: props و context . يتم تمرير هذه props من المكوّن إلى setup() ، وهي تجعل من الممكن الوصول إلى الخاصيّات التي يمتلكها المكوّن من داخل واجهة برمجة التطبيقات الجديدة هذه. هذه الطريقة مفيدة بشكل خاص لأنها تسمح بتدمير الأشياء دون فقد تفاعلها.

 <template> <p>{{ cars.number }}</p> </template> <script> export default { props: { cars: { type: Object, required: true, }, gender: { type: String, required: true, }, }, setup(props) { console.log(props); // prints {gender: "female", cars: Proxy} }, }; </script> <style></style>

لاستخدام قيمة كائن من props في Composition API مع التأكد من أنها تحافظ على تفاعلها ، فإننا نستخدم toRefs . تأخذ هذه الطريقة كائنًا تفاعليًا وتحوله إلى كائن عادي حيث تصبح كل خاصية من خصائص الكائن التفاعلي الأصلي ref . ما يعنيه هذا هو أن cars تدعم ...

 cars: { number: 0 }

... سيصبح الآن هذا:

 { value: cars: { number: 0 }

باستخدام هذا ، يمكننا الاستفادة من cars داخل أي جزء من واجهة برمجة تطبيقات الإعداد مع الحفاظ على تفاعلها.

 setup(props) { let { cars } = toRefs(props); console.log(cars.value); // prints {number: 0} },

يمكننا مشاهدة هذا المتغير الجديد باستخدام watch Composition API والرد على هذا التغيير ولكننا قد نرغب في ذلك.

 setup(props) { let { cars } = toRefs(props); watch( () => cars, (cars, prevCars) => { console.log("deep ", cars.value, prevCars.value); }, { deep: true } ); }

toRef

حالة استخدام شائعة أخرى يمكن أن نواجهها هي تمرير قيمة ليست بالضرورة كائنًا بل هي أحد أنواع البيانات التي تعمل مع ref (مصفوفة ، رقم ، سلسلة ، منطقية ، إلخ). باستخدام toRef ، يمكننا إنشاء خاصية تفاعلية (أي ref ) من كائن تفاعلي المصدر. سيؤدي القيام بذلك إلى ضمان بقاء الخاصية متفاعلة وسيتم تحديثها كلما تغير المصدر الأصلي.

 const cars = reactive({ Toyota: 1, Honda: 0 }) const NumberOfHondas = toRef(state, 'Honda') NumberOfHondas.value++ console.log(state.Honda) // 1 state.Honda++ console.log(NumberOfHondas.value) // 2

هنا ، أنشأنا جسمًا تفاعليًا باستخدام طريقة reactive ، مع خصائص Toyota و Honda . استخدمنا أيضًا toRef لإنشاء متغير تفاعلي من Honda . من المثال أعلاه ، يمكننا أن نرى أنه عندما نقوم بتحديث Honda باستخدام كائن cars التفاعلية أو NumberOfHondas ، يتم تحديث القيمة في كلتا الحالتين.

هذه الطريقة متشابهة ولكنها مختلفة تمامًا عن طريقة toRefs التي تناولناها أعلاه بمعنى أنها تحافظ على ارتباطها بمصدرها ويمكن استخدامها للسلاسل والمصفوفات والأرقام. على عكس toRefs ، لا داعي للقلق بشأن وجود الخاصية في مصدرها وقت الإنشاء ، لأنه إذا لم تكن هذه الخاصية موجودة في الوقت الذي تم فيه إنشاء هذا ref وعوضًا عن ذلك ، null مخزنة كخاصية صالحة ، مع وضع شكل watcher ، بحيث عندما تتغير هذه القيمة ، سيتم أيضًا تحديث ref الذي تم إنشاؤه باستخدام toRef .

يمكننا أيضًا استخدام هذه الطريقة لإنشاء خاصية تفاعلية من props . سيبدو هذا كالتالي:

 <template> <p>{{ cars.number }}</p> </template> <script> import { watch, toRefs, toRef } from "vue"; export default { props: { cars: { type: Object, required: true, }, gender: { type: String, required: true, }, }, setup(props) { let { cars } = toRefs(props); let gender = toRef(props, "gender"); console.log(gender.value); watch( () => cars, (cars, prevCars) => { console.log("deep ", cars.value, prevCars.value); }, { deep: true } ); }, }; </script>

هنا ، أنشأنا ref يستند إلى خاصية gender التي تم الحصول عليها من props . يكون هذا مفيدًا عندما نريد إجراء عمليات إضافية على دعامة مكون معين.

خاتمة

في هذه المقالة ، نظرنا في كيفية عمل التفاعلية في Vue باستخدام بعض الأساليب والوظائف التي تم تقديمها حديثًا من Vue 3. بدأنا بالنظر في ماهية التفاعل وكيف يستخدم Vue كائن Proxy وراء الكواليس لتحقيق ذلك. نظرنا أيضًا في كيفية إنشاء كائنات تفاعلية باستخدام reactive وكيفية إنشاء خصائص تفاعلية باستخدام ref .

أخيرًا ، نظرنا في كيفية تحويل الكائنات التفاعلية إلى كائنات عادية ، كل من خصائصها عبارة عن ref يشير إلى الخاصية المقابلة للكائن الأصلي ، ورأينا كيفية إنشاء ref لخاصية على كائن مصدر تفاعلي.

مزيد من الموارد

  • "وكيل" (كائن) ، MDN Web Docs
  • "أساسيات التفاعل" ، Vue.js
  • "الحكام" ، Vue.js
  • "Lifecycle Hook Registration Inside setup " ، Vue.js