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