Composition API: setup()
کاربرد عمومی
هوک setup()
در شرایط زیر، زمانی که قصد استفاده از Composition API را داریم، به عنوان اولین قدم استفاده میشود:
- استفاده از Composition API بدون مرحله ساخت (build)
- ترکیب کدهای نوشته شده با Composition API در یک کامپوننت با ساختار Options API
نکات تکمیلی
اگر از کامپوننت های تک فایلی (Single-File) با Composition API استفاده میکنید، برای داشتن کدهای کوتاهتر و ارگونومیکتر توصیه میشود از <script setup>
استفاده کنید.
با استفاده از Reactivity APIs و گرفتن خروجی از یک آبجکت از تابع setup()
، میتوان reactive state را تعریف نمود. پراپرتیهای آبجکتی که از آن خروجی گرفتهایم نیز در نمونه ساخته شده از کامپوننت، قابل دسترس خواهد بود (به شرط آنکه سایر آپشنها نیز استفاده شوند):
vue
<script>
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
// expose to template and other options API hooks
return {
count
}
},
mounted() {
console.log(this.count) // 0
}
}
</script>
<template>
<button @click="count++">{{ count }}</button>
</template>
خروجی refs زمانی که در تمپلیت قابل دسترس باشد، بصورت خودکار از setup
تفکیک میشود، در نتیجه برای دسترسی به آن نیازی به استفاده از .value
نیست. علاوه بر این، در شرایطی که از this
استفاده میکنیم نیز به صورت خودکار تفکیک خواهند شد.
تایع setup()
به تنهایی دسترسی به نمونه ساخته شده از کامپوننت را ندارد - در تابع setup()
عبارت this
مقدار تعریف نشده (undefined
) دارد. تنها میتوان از طریق Options API به مقادیر Composition-API-exposed دسترسی داشت، و نه برعکس.
تابع setup()
باید یک آبجکت از نوع synchronously خروجی دهد. تنها زمانی میشود از async setup()
استفاده کرد که کامپوننت از نوع Suspense باشد.
دسترسی به Props
اولین آرگومان تابع setup
مقادیر props
میباشد. درست همانند سایر کامپوننتهای استاندارد، مقدار props
درون تایع setup
متغیر بوده و با پاس دادن متغیر جدید، به روز رسانی خواهد شد.
js
export default {
props: {
title: String
},
setup(props) {
console.log(props.title)
}
}
توجه داشته باشید که با تعمیم (destructure) کردن آبجکت props
، متغیرهای تعمیم دادهشده دینامیک بودن خود را از دست میدهند. درنتیجه توصیه میشود همواره از طریق فرم props.xxx
به مقادیر props
دسترسی داشته باشید. اما اگر اصرار به تعمیم دادن متغیرهای درونی props دارید، یا اینکه با حفظ دینامیک بودن آن قصد پاس کردن یک prop به تابع خارجی را دارید، میتوان از APIهای toRefs() یا toRef() استفاده کنید:
js
import { toRefs, toRef } from 'vue'
export default {
setup(props) {
// turn `props` into an object of refs, then destructure
const { title } = toRefs(props)
// `title` is a ref that tracks `props.title`
console.log(title.value)
// OR, turn a single property on `props` into a ref
const title = toRef(props, 'title')
}
}
آبجکت Setup Context
دومین آرگومانی که به تابع setup
داده میشود، آبجکت Setup Context میباشد. سایر پارامترهایی که ممکن است در تابع setup
استفاده گردد، از طریق این آبجکت وارد میشود:
js
export default {
setup(props, context) {
// Attributes (Non-reactive object, equivalent to $attrs)
console.log(context.attrs)
// Slots (Non-reactive object, equivalent to $slots)
console.log(context.slots)
// Emit events (Function, equivalent to $emit)
console.log(context.emit)
// Expose public properties (Function)
console.log(context.expose)
}
}
از آنجا که آبجکت context دینامیک نمیباشد، با اطمینان خاطر قابل تعمیم دادن است:
js
export default {
setup(props, { attrs, slots, emit, expose }) {
...
}
}
مقادیر attrs
و slots
آبجکتهای stateful هستند و همیشه با آپدیت شدن کامپوننت، مقادیر تازه دریافت میکنند. این بدین معنا است که مقادیر آنها نباید تعمیم داده شوند و باید بصورت attrs.x
یا slots.x
مورد استفاده قرار گیرند. توجه داشته باشید که برخلاف props
، مقادیر attrs
و slots
دینامیک (reactive) نیستند. اعمال تاثیرات جانبی (side effects) روی مقادیر attrs
و slots
باید در چرخه عمر (lifecycle) هوک انجام شود.
استفاده از مقادیر عمومی
تابع expose
زمانی که مقادیر نمونه ساخته شده از کامپوننت، توسط کامپوننت مادر از طریق template refs در دسترس قرار گرفته باشد، برای محدودسازی صریح این مقادیر مورد استفاده قرار میگیرد:
js
export default {
setup(props, { expose }) {
// make the instance "closed" -
// i.e. do not expose anything to the parent
expose()
const publicCount = ref(0)
const privateCount = ref(0)
// selectively expose local state
expose({ count: publicCount })
}
}
استفاده با Render Functions
تابع setup
میتواند یک خروجی از نوع render function نیز داشته باشد. از این طریق میتوان بصورت مستقیم از reactive state تعریف شده در اسکوپ (scope) استفاده کرد:
js
import { h, ref } from 'vue'
export default {
setup() {
const count = ref(0)
return () => h('div', count.value)
}
}
زمانی که یک render function خروجی داده میشود، امکان خروجی گرفتن از مقادیر دیگر وجود ندارد. زمانی که مقادیر تنها در این کامپوننت استفاده شوند، مشکلی برای ما بوجود نمیآورد. اما در حالتی که نیاز باشد توابع کامپوننت از طریق template refs به کامپوننت مادر ارجاع داده شوند، این روش مشکل ساز خواهد بود. با فراخواندن تابع expose()
میتوان این مشکل را برطرف نمود:
js
import { h, ref } from 'vue'
export default {
setup(props, { expose }) {
const count = ref(0)
const increment = () => ++count.value
expose({
increment
})
return () => h('div', count.value)
}
}
تابع increment
از طریق template ref در کامپوننت مادر قابل دسترسی خواهد بود.