Computed property

Computed property

مقدمه

تا به اینجای آموزش آموختیم که Vue چگونه Local State ها (تمام چیزهایی که به طور طبیعی و معمول در کامپوننت ها قرار داشته و استفاده می شود یا به عبارت دیگر همان اطلاعاتی که در داخل data تعریف می کنیم)، و کاپوننت ها، prop های خودشان را مدیریت می کنند. با این حال یک نوع دیگری از خاصیت های Vue وجود دارد که به آن Computed property گفته می شود که در این قسمت، آن را برای شما شرح خواهیم داد.

برای این که مفاهیم مربوط به این خاصیت را بهتر یاد بگیریم، در ادامه یک مثال ساده را با هم انجام خواهیم داد.

<head>
    <title>Sokan-Vuejs-basic (part6)</title>
</head>
<body>
<div id="app">
   <age-calculator></age-calculator>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    Vue.component('age-calculator', {
        template: `
        <p>
“اسم ”افرادی که تعدادی" روز “زندگی کردند               
        </p>
      `
    });
    const app = new Vue({
        el: '#app'
    });
</script>
</body>
</html>

در این مثال از یک کامپوننت با اسم <age-calculator> استفاده شده که تنها یک تگ <P> را در خروجی نمایش می دهد. این تگ حاوی جمله ای است که اسم افراد و یک عبارت محاسباتی را نمایش می دهد.

در نظر داشته باشید که در Vue ، کامپوننت <age-calculator> با id=app به تگ <div> مربوط به آن ارجاع داده شده و در آنجا نمایش داده می شود.

اگر اطلاعات اولیه و این مفاهیم از Vue را از یاد برده­اید و می توانید به بخش های قبلی این آموزش مراجعه کرده و دوباره این مباحث رو مطالعه کنید.

زمانی که استفاده از یک خاصیت دیگر کافی نیست!

قبل از اینکه به ادامه ی توضیحات بپردازیم، مثال بالا را با هم بررسی می کنیم. کامپوننت استفاده شده، باید اسم افراد و تعداد روزهایی که این افراد زندگی کرده اند را در خروجی نمایش دهد. برای این کار در ابتدا به یک آرایه برای ذخیره ی اسم و اطلاعات افراد نیاز است تا بتوانیم با ایجاد یک حلقه درون این آرایه، به تعداد افراد مختلف، کامپوننت تولید کرده و تعداد روزهای محاسبه شده را برای هر فرد نشان دهیم.

حال آرایه ی مورد نظر را به data اضافه می کنیم:

const app = new Vue({
    el: '#app',
    data: {
        people: [
            {name: 'علی', age: 38},
            {name: 'محمد', age: 38},
            {name: 'مصطفی', age: 31},
            {name: 'جواد', age: 20},
            {name: 'نادر', age: 32},
            //Add more yourself
        ]
    }
});

اکنون یک حلقه v-for روی خود کامپوننت به ازای هر فرد و با یک کلید منحصر به فرد ایجاد می کنیم.

<div id="app">
    <age-calculator v-for="person in people" :key="person.name"></age-calculator>
</div>

بسیار خب، حالا آرایه ای از اسم افراد را که در data تعریف کرده ایم، به عنوان prop به درون کامپوننت می فرستیم. البته فراموش نکنیم که ابتدا باید این آرایه را درون خود <age-calculator> به عنوان prop تعریف کرده و به کامپوننت معرفی کنیم.

Vue.component('age-calculator', {
    props: {
        person: {
            type: Object,
            required: true
        }
    },
    template: `
      <p>
 {{ person.name }} فردی است که تعدادی روز زندگی کرده است.        
      </p>
    `
});

در رابطه با این قسمت از مثال باید گفت، از قبل یاد گرفته ایم که می توان props ها را به شکل props: [‘person’] (آرایه ای از کلمه ها) تعریف کرد و این روش در بیشتر مواقع جواب می دهد. اما چطور می توان روی این آرایه و مقادیر ورودی که کامپوننت دریافت می کند کنترل بیشتری داشت؟!

در این گونه موارد و همان طور که در مثال استفاده شد، می توان با مشخص کردن نوع ورودی (type) و برابر قراردادن آن با object به کامپوننت معرفی کرد که آرایه ی ورودی دارای مقادیری از نوع object بوده و کامپوننت از دریافت انواع دیگری از ورودی ها جلوگیری خواهد کرد. همچنین با مشخص کردن نوع ورودی، در ادامه می توان به راحتی مقادیر دیگری را هم به آرایه ی مورد نظر اضافه کرد و کامپوننت محدود نخواهد شد.

علاوه بر type که نوع ورودی را مشخص می کند، متغیر required یک Boolean است که اجباری بودن یا نبودن ورودی ها را برای تولید خروجی توسط کامپوننت، مشخص می کند.

همچنین می توان از مقدار دیگری برای کنترل بهتر ورودی ها استفاده کرد که default نامیده می شود و یک مقدار اولیه برای props در نظر می گیرد که ما در این مثال نیازی به مقدار اولیه نداشتیم.

قبل از اجرای کد و دیدن نتیجه، تنها کافی است یک بخش دیگر اضافه شود...

بعد از تعریف آرایه ی ورودی در <age-calculator> ، باید این آرایه از بیرون کامپوننت به عنوان props داده شود. در قسمتی که حلقه ایجاد کرده ایم، این متغیر را به شکل bind شده به کامپوننت می دهیم.

<age-calculator
        v-for="person in people"
        :person="person"
        :key="person.name"
></age-calculator>

دقت داشته باشید که در حلقه باید person به عنوان props به کامپوننت داده شود نه people.

توجه: برای توضیح بیشتر در رابطه با خاصیت required برای یک props باید گفت که اگر فراموش کنیم آرایه ی person را به عنوان props به کامپوننت بدهیم و چون در داخل کامپوننت خاصیت required این آرایه را برابر با true قرار داده ایم، پس از اجرای کد در قسمت console مرورگر با خطای زیر مواجه می شویم:

عملکرد و روش استفاده از خاصیت computed

برای تکمیل مثال بالا تنها یک قسمت باقیست تا به عنوان ورودی به کامپوننت مورد نظر بدهیم. باید تعداد روزهایی که افراد زنده بوده اند را محاسبه کنیم.

این محاسبه سخت نیست و تنها باید عدد 365 را در سن این افراد ضرب کرد. اولین و ساده ترین راه ممکن این است که این عملیات را به همان شکلی که به ذهن ما میرسد، ضرب کرده و به طور مستقیم درون تگ <p> قرار دهیم.

template: `
  <p>
  {{ person.name }} فردی است که {{ person.age * 365 }} روز زندگی  کرده است .
  </p>
`

این روش، جواب می دهد. اما اگر محاسبات ما سخت تر و پیچیده تر باشد به چه شکلی باید این محاسبات را انجام داد؟! برای مثال اگر برای محاسبه یک عملیات بخواهیم از حلقه ها و یا دستورهای شرطی نظیر (if, or, and,…) استفاده کنیم، حتما به مشکل بر می خوریم.

در اینجا تأثیر computed properties نمایان می شود. خاصیت computed به شیوه ای همان توابع (function) هستند که تکه کدی را اجرا کرده و خروجی را نشان می دهند در این صورت، ما به طور مستقیم می توانیم از این خروجی استفاده کنیم.

شیوه استفاده و تعریف یک computed را در ادامه با هم می بینیم که در کد زیر محل قرارگیری computed ها درون کامپوننت مشخص شده است.

Vue.component('age-calculator', {
    props: {
        person: {
            type: Object,
            required: true
        }
    },
    template: `
      <p>
 {{ person.name }} فردی است که {{ person.age * 365 }} روز زندگی   کرده است   .
      </p>
    `,
    computed: {
        // Computed props go here
    }
});

در حقیقت این ساختار دقیقا همانند ساختاری است که ما برای تعریف methods استفاده می کنیم. در اصل خود computed ها نیز ساختاری شبیه به تابع دارند و حتی در این مثال از آن ها نیز می توان استفاده کرد که در ادامه به شکل کامل، تفاوت ها و شباهت های این دو را برای شما شرح خواهیم داد.

بعد از تعریف محلِ قرارگیری  computedها در کامپوننت باید یک خاصیت از جنس computed با نام daysAlive تعریف کنیم که ساختاری مشابه تابع داشته و دارای خروجی مشخصی باشد.

computed: {
    daysAlive() { //Remember, computed props are functions in the end
        return this.person.age * 365
    }
}

در نظر بگیرید که همانند تابع، برای دسترسی به ورودی person در کامپوننت باید از this قبل از person استفاده کرد و تنها درون خود template می توانیم از ورودی ها به شکل مستقیم استفاده کنیم.

اکنون از computed تعریف شده(daysAlive)  درون template استفاده می کنیم:


template: `
  <p>
 {{ person.name }} فردی است که {{ daysAlive }} روز زندگی کرده است.	
  </p>
`

خروجی daysAlive به عنوان یک computed همانند props در کنار اطلاعات دیگر ورودی ها به نمایش در می آید.

در حقیقت این computed ها در Vuejs به گونه ای عمل می کنند که به راحتی می توان از آن ها در دیگر توابع در بخش methods استفاده کرد. به عبارت دیگر computed ها در برنامه به شکل یک prop و یا همان متغیر دیده می شوند.

تفاوت methods و خاصیت computed

به یقین تاکنون متوجه این شده اید که شباهت های بسیاری بین methods و computed ها وجود دارد. به معنای دیگر این دو، در سطح کد به طور کامل شبیه به هم هستند اما در ساختار درونی دارای تفاوت های جالبی هستند که نیاز است با آن ها آشنا شوید.

مقادیر Computed ها ذخیره می شوند.

در ساده ترین شکل ممکن می توان گفت که Vue، کدها را می خواند و منتظر تغییرات می ماند. سپس با کوچک ترین تغییرات در data و props دوباره مقدار computed ها را محاسبه کرده و خروجی را نمایش می دهد. اما اگر تغییراتی در داده های اولیه ایجاد نشود، Vue دوباره مقادیر را محاسبه نمی کند و از همان مقادیر قبلی که به وسیله computed ها محاسبه و ذخیره شده، استفاده کرده و نمایش می دهد.

اما در مقابل، توابع، در همه حال اجرا می شوند و حتی در صورت ثابت بودن مقادیر اولیه باز هم دوباره اجرا می شوند و خروجی را محاسبه می کنند. هیچ ذخیره ای درکار نبوده و همانند مابقی توابع در دیگر زبان ها اجرا می شوند.

در مثالی که گفته شد، یک محاسبه ی خیلی ساده انجام شد و برای اینگونه محاسبه ها، اجباری در استفاده از computed ها نیست. به عبارت دیگر در اینگونه مثال ها و کاربردهای ساده، توابع و computed ها از لحاظ عملکردی هیچ تفاوتی نخواهند داشت. اما زمانی که کدهای سنگین نوشته شده و هزاران کامپوننت در پروژه به کار برده می شود، این ذخیره شدن مقادیر و دوباره اجرا نشدن computed ها به چشم خواهد آمد.

برای توضیح بیشتر در مورد مثال گفته شده در بالا، computed استفاده شده، در مرحله دوم حلقه for اجرا نمی شود. زیرا Vue مقدار خروجی از مرحله ی قبلی را ذخیره کرده و به دلیل اینکه مقدار اولیه سن "محمد" نسبت به مقدار سن "علی" تغییر نکرده است، Vue همان مقدار قبلی را در خروجی نمایش می دهد.

کد کامل مثال مربوطه را در این قسمت دوباره برایتان قرار داده ایم:

<html>
<head>
    <title>Sokan-Vuejs-basic (part6)</title>
</head>
<body>
<div id="app">
    <age-calculator
            v-for="person in people"
            :person="person"
            :key="person.name"></age-calculator>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script>
    Vue.component('age-calculator', {
        props: {
            person: {
                type: Object,
                required: true
            }
        },
        template: `
          <p>
          {{ person.name }} فردی است که {{ daysAlive }} روز زندگی کرده است.
          </p>
        `,
        computed: {
            daysAlive() { //Remember, computed props are functions in the end
                return this.person.age * 365
            }
        }
    });
    const app = new Vue({
        el: '#app',
        data: {
            people: [
                {name: 'علی', age: 38},
                {name: 'محمد', age: 38},
                {name: 'مصطفی', age: 31},
                {name: 'جواد', age: 20},
                {name: 'نادر', age: 32},
                //Add more yourself
            ]
        }
    });
</script>
</body>
</html>

اگر می خواهید در مورد computed ها و عملکرد آن ها اطلاعات بیشتری کسب کنید از سایت زیر استفاده کنید

https://vuejs.org/v2/guide/computed.html

نظرات
اگر login نکردی برامون ایمیلت رو بنویس: