جزئیات تکمیلی در مورد Mixinها

Additional Details about Mixins

Vue.JS 2: جزئیات تکمیلی در مورد Mixin ها - قسمت 57

به قسمت آخر از این فصل خوش آمدید. در قسمت قبل کد زیر را داشتیم:

<script>
import List from "./List.vue";
import { fruitMixin } from "./fruitMixin";

export default {
  mixins: [fruitMixin],
  data() {
    return {
      text: "Hello there!"
    };
  },
  filters: {
    toUppercase(value) {
      return value.toUpperCase();
    }
  },
  components: {
    appList: List
  }
};
</script>

نکته جالبی که در مورد این کد وجود دارد این است که import کردن mixin ها باعث نابودی شیء Vue ما یا اطلاعات درون آن نمی شود بلکه با دقت دو مقدار را روی هم merge (ادغام) می کند. نکته بعدی اینجاست که اگر درون Mixin ها از lifecycle hook ها استفاده کنید و سپس درون شیء Vue نیز از lifecycle hook دیگری استفاده کنید، هر دو اجرا می شوند حتی اگر همنام باشند! ترتیب اجرا شدنشان نیز بدین صورت است:

  1. ابتدا Mixin اجرا می شود.
  2. سپس کدهای دیگر کامپوننت اجرا می شوند.

بگذارید با یک مثال این مسئله را برایتان روشن کنم. من به فایل fruitMixin.js می روم و از lifecycle hook ای به نام Created استفاده می کنم:

export const fruitMixin = {
    data() {
        return {
            fruits: ["Apple", "Banana", "Mango", "Melon"],
            filterText: ""
        };
    },
    computed: {
        filteredFruits() {
            return this.fruits.filter(element => {
                return element.match(this.filterText);
            });
        }
    },
    created() {
        console.log('Created');
    }
}

برای اینکه فهم موضوع ساده باشد فقط از یک دستور log استفاده کرده ام. حالا اگر مرورگر را باز کرده و صفحه را refresh کنیم، عبارت created دو بار در قسمت کنسول نمایش داده می شود:

log شدن lifecycle hook (دو بار)
log شدن lifecycle hook (دو بار)

چرا؟ به دلیل اینکه فایل های App.vue و List.vue از این Mixin استفاده می کنند بنابراین هر دو، کدهای آن را اجرا می کنند. بیایید فرض دیگری داشته باشیم. اگر وارد فایل List.vue شده و دوباره از lifecycle hook ای به نام created استفاده کنیم چه اتفاقی می افتد؟ به کد زیر از فایل List.vue توجه کنید:

<script>
import { fruitMixin } from "./fruitMixin";

export default {
  mixins: [fruitMixin],
  created() {
    console.log("Inside List Created Hook");
  }
};
</script>

مقدار log شده در این کد Inside List Created Hook است که به فارسی یعنی created ای که درون List وجود دارد. اگر این کد را ذخیره کرده و مرورگر را باز کنیم با این صحنه روبرو می شویم:

مشاهده ی ترتیب اجرای کد ها بین کامپوننت و mixin
مشاهده ترتیب اجرای کدها بین کامپوننت و mixin

منظور من از ترتیب اجرا شدن کدها همین بود. ابتدا Mixin اجرا می شود و سپس کدهای درون component. چرا؟ به دلیل اینکه با این روش کامپوننت می تواند کدهای Mixin را overwrite کند (باطل کرده و کدهای خودش را اعمال کند) تا اگر تناقضی وجود داشت، mixin نتواند جزئیات کامپوننت ها را نابود کند.

مسئله بعدی Mixin های سراسری یا Global Mixins است. شاید یک Mixin ای داشته باشیم که بخواهیم از آن روی تک تک کامپوننت های خود استفاده کنیم. ما تقریبا هیچگاه از mixin های سراسری استفاده نمی کنیم چرا که روی همه برنامه اجرا می شوند. Documentation رسمی وب سایت Vue.js می گوید که mixin های سراسری معمولا فقط برای ساخت پلاگین برای فریم ورک Vue کاربرد دارند نه روی برنامه های واقعی. در عین حال دوست دارم نحوه ساخت آن ها را بدانید.

برای این کار ابتدا به فایل main.js رفته و می گوییم:

import Vue from 'vue'
import App from './App.vue'

Vue.filter('to-lowercase', function (value) {
  return value.toLowerCase();
});

Vue.mixin({
  created() {
    console.log('Global Mixin - Created Hook');
  }
})

اگر چنین کاری بکنیم، نیازی به دستور import نیست و mixin ما به صورت خودکار به تمام کامپوننت ها اضافه می شود. حالا به مرورگر می رویم و ترتیب اجرا شدن را می بینیم:

در این تصویر مشاهده می شود که global mixin ها نیز اجرا و چاپ شده اند
در این تصویر مشاهده می شود که global mixin ها نیز اجرا و چاپ شده اند

سوال: ما دو کامپوننت داریم: App.vue و List.vue اما global mixin ما 3 بار اجرا شده است! چرا؟

پاسخ: ما درون فایل main.js یک شیء Vue دیگر را نیز داریم. دقیقا پایین تر از Mixin سراسری خودمان:

import Vue from 'vue'
import App from './App.vue'

Vue.filter('to-lowercase', function (value) {
  return value.toLowerCase();
});

Vue.mixin({
  created() {
    console.log('Global Mixin - Created Hook');
  }
})

new Vue({
  el: '#app',
  render: h => h(App)
})

با این حساب بر اساس تصویر بالا از کنسول مرورگر می گوییم:

  1. اولین مقدار (Global Mixin – Created Hook) مربوط به شیء Vue درون فایل js است (کد بالا). این شیء کامپوننت app# را نمایش می دهد (در کد بالا مشخص است که به el پاس داده شده است) بنابراین کامپوننت بعدی App.vue است.
  2. دومین مقدار (Global Mixin – Created Hook) مربوط به vue است.
  3. فایل vue از fruitMixin استفاده می کند بنابراین در این مرحله fruitMixin صدا زده می شود و سومین مقدار (Created) نمایش داده می شود.
  4. فایل vue از کامپوننت List.vue نیز استفاده می کند بنابراین مقدار چهارم (Global Mixin – Created Hook) مربوط به List.vue است.
  5. مقدار پنجم (Created) مربوط به fruitMixin درون فایل vue است که یک بار دیگر اجرا می شود.
  6. نهایتا مقدار (Inside List Created Hook) چاپ شده است که مربوط به created (تعریف شده در vue) می باشد.

خلاصه این توضیحات به شکل زیر است:

خلاصه ی کنسول مرورگر پس از چاپ mixin ها
خلاصه کنسول مرورگر پس از چاپ mixin ها

سوال بسیار مهم: اگر data را درون mixin تغییر بدهیم چه اتفاقی می افتد؟ آیا data درون mixin بین تمام کامپوننت ها به اشتراک گذاشته می شود یا اینکه برای هر کامپوننت یک نمونه جدا از Data ساخته می شود و از هم مستقل هستند؟

پاسخ: کدهای mixin به اشتراک گذاشته نمی شود و هر کدام از کامپوننت ها یک کپی جداگانه از آن را دریافت می کنند. بنابراین اگر کدهای data را درون App.vue تغییر بدهیم، data درون List.vue تغییر نخواهد کرد. اگر بخواهید آن را به اشتراک بگذارید باید شیء خود را (مثلا اینجا فایل fruitMixin.js) به شکل عادی import کنید نه اینکه به عنوان یک mixin ثبت نمایید. همچنین استفاده از Event Bus که در جلسات قبل در موردش صحبت کردیم راه حل خوبی است.

تمام فصل‌های سری ترتیبی که روکسو برای مطالعه‌ی دروس سری آموزش رایگان Vue js از صفر تا صد توصیه می‌کند:
نویسنده شوید
دیدگاه‌های شما

در این قسمت، به پرسش‌های تخصصی شما درباره‌ی محتوای مقاله پاسخ داده نمی‌شود. سوالات خود را اینجا بپرسید.