淺析在Vue中watch使用的必要性及其優(yōu)化
場(chǎng)景
代碼大概如下,刪除了很多無(wú)關(guān)內(nèi)容。
<template>
<div>
<SearchBar @search="handleSearch" />
<Pagination
v-model:page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
/>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, watch, inject, computed } from 'vue'
import SearchBar from '@/components/SearchBar.vue'
const route = useRoute()
const pagination = reactive({
page: 1,
pageSize: isPublic.value ? 10 : 9,
total: 0,
})
const keyword = ref('')
const fetchList = async () => {
loading.value = true
const res = await connect.get(`/api/${route.params.type}`, {
params: {
pageSize: pagination.pageSize,
page: pagination.page,
name: keyword.value,
},
})
pagination.total = res.total
loading.value = false
}
watch(
() => route.params.type,
async () => {
pagination.page = 1
fetchList()
},
{ immediate: true }
)
watch(
() => pagination.page,
async () => {
fetchList()
}
)
watch(
() => keyword.value,
async () => {
if (pagination.page === 1) fetchList()
else {
pagination.page = 1
}
}
)
const handleSearch = (val: string) => {
keyword.value = val
}
const handleDelete = async (item: MindMapItem) => {
await confirmModal.value?.confirm()
await connect.delete('/api/map/' + item._id)
fetchList()
}
</script>
本來(lái)只有 2 個(gè) watch,今天新功能加了個(gè)關(guān)鍵詞搜索,又得多 watch 一個(gè) keyword.value。
于是這里變成了 3 個(gè) watch,而且里面有邏輯,甚至是相互依賴的邏輯。
上面的代碼沒寫完,但是整理一下,最終目標(biāo)是這樣的:
- 請(qǐng)求參數(shù)有三個(gè)變量:route.params.type、keyword 和 pagination
- route.params.type 改變時(shí)需要重置 pagination 和 keyword,然后重新請(qǐng)求
- keyword 改變時(shí)需要重制 pagination,然后重新請(qǐng)求
- pagination 改變時(shí)需要重新請(qǐng)求
watch 真的好?
如果繼續(xù)用 watch,因?yàn)樾枰刂?pagination 和 keyword,硬生生把三個(gè) watch 寫成了個(gè)像是任務(wù)委托一樣的效果,例如 keyword.value 修改時(shí)如果 page 是 1 就直接請(qǐng)求,否則修改 page 再讓 page 的 watch 觸發(fā)請(qǐng)求。
watch(
() => keyword.value,
async () => {
if (pagination.page === 1) fetchList()
else {
pagination.page = 1
}
}
)
這么耦合真的好嗎?這不好。我勸自己耗子尾汁,好好反思。
得出的結(jié)論是:watch 不是好文明,能不用 watch,就別用 watch。
這不是我第一次對(duì) watch 有意見,在工作中我就見過(guò)很多復(fù)雜組件動(dòng)則 5 個(gè)以上的 watch,有的里面還有復(fù)雜邏輯。
重點(diǎn)是啥,還沒注釋……watch 天然就容易讓人不寫注釋,給人一種“啊,這個(gè)值變了,運(yùn)行下面的邏輯是理所當(dāng)然的吧。”,那你問(wèn)問(wèn)兩個(gè)月后的自己,是不是真的這樣?你自己寫的 watch 你自己看得懂嗎?一個(gè)值變了就觸發(fā)邏輯,但問(wèn)題是,它變的原因可多了。
所以 watch 生而在語(yǔ)義上不明確,它只解釋了對(duì)值的依賴,沒有解釋依賴的原因。
watchEffect 呢?
上面的例子,假如把 fetchList 寫成 watchEffect,其實(shí)還是一樣的問(wèn)題,需要在里面額外加 if else 處理重置邏輯。不過(guò)邏輯集中在一個(gè) watchEffect 大概還是比分散在 N 個(gè) watch 里好。
總結(jié)
總結(jié)一下,watch 或者 watchEffect 有其用武之地,但最好滿足以下的條件:
- 變動(dòng)觸發(fā)點(diǎn)大于 2 個(gè)才考慮
watch(只有一個(gè)觸發(fā)機(jī)會(huì)的話,什么時(shí)候用,什么時(shí)候跑就好了) - 所有場(chǎng)景全都適用同一個(gè)處理邏輯
- 與其他 watch 沒耦合
不過(guò)如果沒有事件機(jī)制來(lái)觸發(fā)的話,那就只能 watch 了。
優(yōu)化后
<template>
<div>
<SearchBar @search="handleSearch" />
<Pagination
v-model:page="pagination.page"
@update:page="fetchList"
:page-size="pagination.pageSize"
:total="pagination.total"
/>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, watch, inject, computed } from 'vue'
import SearchBar from '@/components/SearchBar.vue'
const route = useRoute()
const pagination = reactive({
page: 1,
pageSize: isPublic.value ? 10 : 9,
total: 0,
})
const keyword = ref('')
const fetchList = async () => {
// 省略
}
watch(
() => route.params.type,
async () => {
keyword.value = ''
pagination.page = 1
fetchList()
},
{ immediate: true }
)
const handleSearch = (val: string) => {
keyword.value = val
pagination.page = 1
fetchList()
}
const handleDelete = async (item: MindMapItem) => {
await confirmModal.value?.confirm()
await connect.delete('/api/map/' + item._id)
fetchList()
}
</script>
修改后,只保留 route.params.type 的 watch,不會(huì)發(fā)生沖突,另外兩個(gè)通過(guò)事件觸發(fā)。至于觸發(fā)事件也不用額外寫 @change,直接用 @update:xxx 就可以了。
這樣只有易讀的重置邏輯,沒有 if else!清爽!
到此這篇關(guān)于淺析在Vue中watch使用的必要性及其優(yōu)化的文章就介紹到這了,更多相關(guān)Vue watch內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue做移動(dòng)端適配最佳解決方案(親測(cè)有效)
這篇文章主要介紹了vue做移動(dòng)端適配最佳解決方案(親測(cè)有效),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
vue限制實(shí)現(xiàn)不登錄無(wú)法進(jìn)入其他頁(yè)面
本文主要介紹了vue限制實(shí)現(xiàn)不登錄無(wú)法進(jìn)入其他頁(yè)面,vue限制不登錄,通過(guò)url進(jìn)入其他頁(yè)面強(qiáng)制回到登錄頁(yè)面;已經(jīng)登錄的情況下,不可以再進(jìn)入登錄界面,感興趣的可以了解一下2024-01-01
element-ui和vue表單(對(duì)話框)驗(yàn)證提示語(yǔ)(殘留)清除操作
這篇文章主要介紹了element-ui和vue表單(對(duì)話框)驗(yàn)證提示語(yǔ)(殘留)清除操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09
vue?el-date-picker?日期回顯后無(wú)法改變問(wèn)題解決
這篇文章主要介紹了vue?el-date-picker?日期回顯后無(wú)法改變問(wèn)題解決,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-04-04
超詳細(xì)教程實(shí)現(xiàn)Vue底部導(dǎo)航欄TabBar
本文詳細(xì)講解了Vue實(shí)現(xiàn)TabBar底部導(dǎo)航欄的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11
vue2和vue3部署到服務(wù)器子目錄為空白頁(yè)問(wèn)題及解決
這篇文章主要介紹了vue2和vue3部署到服務(wù)器子目錄為空白頁(yè)問(wèn)題及解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07
vue使用$store.commit() undefined報(bào)錯(cuò)的解決
這篇文章主要介紹了vue使用$store.commit() undefined報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06

