写 Vue 我建议非必要别用 watch

场景

代码大概如下,删除了很多无关内容。

<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,今天新功能加了个关键词搜索,又得多 watch 一个 keyword.value

于是这里变成了 3 个 watch,而且里面有逻辑,甚至是相互依赖的逻辑。

上面的代码没写完,但是整理一下,最终目标是这样的:

  • 请求参数有三个变量:route.params.type、keyword 和 pagination
  • route.params.type 改变时需要重置 pagination 和 keyword,然后重新请求
  • keyword 改变时需要重制 pagination,然后重新请求
  • pagination 改变时需要重新请求

watch 真的好?

如果继续用 watch,因为需要重置 pagination 和 keyword,硬生生把三个 watch 写成了个像是任务委托一样的效果,例如 keyword.value 修改时如果 page 是 1 就直接请求,否则修改 page 再让 page 的 watch 触发请求。

watch( () => keyword.value, async () => { if (pagination.page === 1) fetchList() else { pagination.page = 1 } } )

这么耦合真的好吗?这不好。我劝自己耗子尾汁,好好反思。

得出的结论是:watch 不是好文明,能不用 watch,就别用 watch

这不是我第一次对 watch 有意见,在工作中我就见过很多复杂组件动则 5 个以上的 watch,有的里面还有复杂逻辑。

重点是啥,还没注释……watch 天然就容易让人不写注释,给人一种“啊,这个值变了,运行下面的逻辑是理所当然的吧。”,那你问问两个月后的自己,是不是真的这样?你自己写的 watch 你自己看得懂吗?一个值变了就触发逻辑,但问题是,它变的原因可多了。

所以 watch 生而在语义上不明确,它只解释了对值的依赖,没有解释依赖的原因。

watchEffect 呢?

上面的例子,假如把 fetchList 写成 watchEffect,其实还是一样的问题,需要在里面额外加 if else 处理重置逻辑。不过逻辑集中在一个 watchEffect 大概还是比分散在 N 个 watch 里好。

总结

总结一下,watch 或者 watchEffect 有其用武之地,但最好满足以下的条件:

  • 变动触发点大于 2 个才考虑 watch(只有一个触发机会的话,什么时候用,什么时候跑就好了)
  • 所有场景全都适用同一个处理逻辑
  • 与其他 watch 没耦合

不过如果没有事件机制来触发的话,那就只能 watch 了。

优化后

<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.typewatch,不会发生冲突,另外两个通过事件触发。至于触发事件也不用额外写 @change,直接用 @update:xxx 就可以了。

这样只有易读的重置逻辑,没有 if else!清爽!

原文传送门:ssshooter.com/vue-watch/

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Vue中,可以手动实现watch功能。手watch的关键在于定义一个名为watch的函数并将其绑定到Vue实例上。下面是一个简单的手watch的示例: ```javascript function watch(obj, prop, callback) { let value = obj[prop]; Object.defineProperty(obj, prop, { get() { return value; }, set(newValue) { const oldValue = value; value = newValue; callback(newValue, oldValue); } }); } const data = { cityName: 'shanghai' }; new Vue({ el: '', data: data, created() { watch(data, 'cityName', (newName, oldName) => { // 处理数据变化的逻辑 }); } }); ``` 在上面的代码中,我们定义了一个名为watch的函数,它接受三个参数:对象obj、属性prop和回调函数callback。函数内部使用了Object.defineProperty方法来监听属性的变化,并在属性发生变化时调用回调函数进行处理。在Vue实例的created生命周期钩子中,我们调用了watch函数来监听data对象的cityName属性,并在属性变化时执行相应的回调函数。通过这种方式,我们实现了手watch功能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【Vuewatch的详细⽤法](https://blog.csdn.net/weixin_43900414/article/details/125143642)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [实现一个mini-vue](https://download.csdn.net/download/m0_51431448/88129585)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子伟-H5

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值