compositon api
# setup
setup 是 Composition Api 的入口,也算是一個 hook,
setup出現的時機 (在 created 之前):- vue 實體創立
- 初始化
props - 調用
setup✅
# props
setup提供第一個參數,就是由父層傳進的props可以藉由此讀取到props的值props: { title: { type: String, required: true } }, setup(props, context) { console.log(props.title) }# context
setup提供第二個參數為context為調問 vue 實例的地方,可以提供 原本 this 的功能- emit
- attrs
- slot
像最常使用到的
$emit就是變為context.emit
setup(props, context) { function setData() { context.emit('set-data', newData) } }
# 🧰 methods
setup 內,直接使用 命名的函式,就是 methods
<script>
const { ref, reactive } = Vue
const App = {
setup() {
const count = ref(0)
const obj = reactive({ count: 0 })
const plus = () => {
count.value++
obj.count++
}
const less = () => {
count.value--
obj.count--
}
return { count, obj, plus, less }
},
}
Vue.createApp(App).mount('#app')
</script>
methods 也是要進行回傳才能被使用
# 🖥 computed
在 setup 中,沒有 computed,變成要引入 computed 函式來操作這個計算方法
computed( ()=>{ // 要回傳的計算值 } )
<script>
const { reactive, computed } = Vue
const App = {
setup() {
const obj = reactive({ count: 0 })
const plus = () => {
obj.count++
}
const total = computed(() => obj.count * 40)
// const copyObj =
return {
obj,
plus,
total,
}
},
}
Vue.createApp(App).mount('#app')
</script>
# setup 內操作 computed
注意
在 setup 裡,使用 computed 產生的參數時,還是需要使用 .value 來提取內容。
不然會是一個被包裝的物件!!(如下) 
const filterList = computed(() => listArr.filter((item) => item.money > 500))
const BoxHeight = computed(() => {
return isOpen.value ? `${filterList.value.length * 40}px` : '0px'
})
# methods 與 compouted 選擇?
兩個方法都可以做到一樣的事情,但在內部運作完全不同!
computed (不可傳入參數) 會緩存計算後的資料,只要資料不變動,就不會再重新執行計算!
methods (可以傳入參數使用) 不會緩存,每次都要重新執行
# 👂 watch
可以透過 watch() 來監聽資料,當指定資料變動時,將會執行裡面的函式。
# 監聽
ref資料watch( ref資料名稱, (新資料, 舊資料)=>{ // 變動時執行函式 } )const { watch, ref } = Vue const App = { setup() { const title = ref('Hello') const text = ref('Wrold') watch(title, (newVal, oldVal) => { console.log(`這是新的值${newVal} 這是舊的值 ${oldVal}`) }) const setTitle = () => { setTimeout(() => { title.value = 'World' }, 1000) } return { title, text } }, }同時監聽多組
ref,使用[]陣列包起watch([title, text], ([newTitle, newText], [preTitle, preText]) => { console.log(` title 新的值:${newTitle} 舊的值: ${preTitle} text 新的值:${newText} 舊的值: ${preText} `) })若
ref為物件 此時就要監聽的對像,必須是函式的返回const data = ref({ id: 1 }) watch( () => data.id, (newVal, oldVal) => { console.log(` data 新的值: ${newVal} , 舊的值:${oldVal} `) } ) const setData = () => { setTimeout(() => { data.value.id = 2 }, 1000) }ref無法監控 物件型別ref({})!!只能指定內部的某一個對象,且使用
() =>(函式回傳) 才可以監控// × const data = ref({ id: 1 }) watch(data, () => {})// ○ const data = ref({ id: 1 }) watch( () => data.id, () => {} )🧨 深度監控掃描!! 非不得已監聽方式,這樣就可以監聽到
ref的變動,但非常耗效能,每次都要掃描內部資料。const data = ref({ id: 1 }) watch(data, () => {}, { deep: true })# 監聽
reactvie資料
reactive 都是 物件型別,所以在監聽整個 物件 時,回調函式只會有一個 參數 更改後的值。
watch( reactiveData, (newVal) => { //要執行的事 } )
const data = reactive({ id: 1 })
watch(data, (newVal) => {
console.log(`這是新的 id: ${newVal}`)
})
const setData = () => {
setTimeout(() => {
data.id = 2
}, 1000)
}
監聽 reactvie 內部,對象必須是函式回調 ()=>
這個時候,在回調函式的 參數 可以使用 新的值與舊的值。
const data = reactive({ id: 1 })
watch(
() => data.id,
(newVal, oldVal) => {
console.log(`
這是新的 id: ${newVal}
這是舊的 id: ${oldVal}
`)
}
)
const setData = () => {
setTimeout(() => {
data.id = 2
}, 1000)
}
監聽多組 reactive
watch(
[() => data.id, () => data2.id],
([newData, newData2], [oldData, oldData2]) => {}
)
有時資料有更動,但 watch 沒有動靜,可能是資料太深層,你可以使用 { deep: true }
來監聽更深層的資料。
# 👁wawtchEffect 追蹤監聽
只要被設置,載入頁面時就會運作,當內部有使用的資料變更時,就會再次 調用
# 監聽方式
只要被放入執行的項目的資料,就會被加入 追蹤監聽,當內部有任何一個資料被更新,就會馬上執行內部的項目。
建立監聽時,載入頁面同時也被執行 !!
watchEffect( ()=> { // 執行項目(同時受監聽) } )const count = ref(0) watchEffect(() => console.log(count.value)) // -> 載入頁面時先 logs 0 setTimeout(() => { count.value++ // -> 資料變動時 logs 1 }, 100)# 停止監聽
當
watchEffect這個方法,在setup或其它生命周期時, 將watchEffect用變數接下,想停止時 執行 這個變數setup() { const count = ref(0) // 將 watchEffect 用變數接起 const stop = watchEffect(() => { console.log(count.value) if (count.value === 5) return stop() // 執行變數函式,將停止 }) // 執行每秒累加 setInterval(() => { count.value++ }, 1000) return { count, } }, }# 停止監聽執行中的非同步
有些時候,你停止了監聽的函式運作,但函式裡如果有非同步函式正在運行,還是會被回傳,這時就需要清掉 非同步的函式運行
如果
非同步函式是一個變數watchEffect((onInvalidate) => { const token = performAsyncOperation(id.value) onInvalidate(() => { // id has changed or watcher is stopped. // invalidate previously pending async operation token.cancel() }) })如果使用
asyncawait要在
await之前,先註冊清除的方法。const data = ref(null) watchEffect(async onInvalidate => { onInvalidate(() => {...}) // we register cleanup function before Promise resolves data.value = await fetchData(props.id) })
# 🆚 watch VS watchEffect
| - | watch | watchEffect |
|---|---|---|
| 說明 | 被動監聽 | 主動監聽 |
| O | 可以拿到參數 新/舊值 | 可以停止監聽 |
| x | 無法停止監聽 | 無法取參數得新/舊值 |
# watch 轉 watchEffect
主動監聽方式 => {immediate: true}
watch(data, () => {}, { immediate: true })