温故而知新(03)------ watch vs watcheffect

前言

由于之前一直使用watch,不怎么使用watchEffect,今天就来简单的看下两者的不同之处

watch

先从简单的代码的使用方法看起:

xml 复制代码
<script setup>
import {watch, ref, reactive, computed} from "vue";

const name = ref('小红');

setTimeout(() => {
  name.value = '小白'
}, 2000)
watch(name, (newval, oldval) => {
  console.log(newval, oldval)
}, {
  deep: false,
  immediate: false
})
</script>
<template>
  <div>
    123456.吐槽,你不说我怎么知道啊
  </div>
</template>

watcht简单的监听只需要三个参数:

1.监听的对象 2.监听后的回调函数,第一个值是新值,第二个值是老值 3.监听时的触发选项,是否深度监听和是否立即监听

监听对象中的某个key:

1.方便的做法是在选项中使用深度监听,配置:{deep:true}这样就可以监听到整个对象是发生了变化的。

2.直接监听对象的某个值,这样还能节约性能。

代码演示如下:

xml 复制代码
<script setup>
import {watch, ref, reactive, computed} from "vue";
const TestObj = ref({
 name:'小红娘',
 age:18,
})

watch(TestObj.value.name,(newval,oldval)=>{
 console.log(newval,oldval)
})
setTimeout(() => {
 TestObj.value.name = '小白'
 console.log(11)
}, 2000)
</script>
<template>
 <div>
   123456.吐槽,你不说我怎么知道啊
 </div>
</template>

运行效果如下,并未打印新旧值

这样的方式不允许我们在vue3中使用,我们在监听某个对象的值时,需要用getter方法导出。

完整代码如下:

xml 复制代码
<script setup>
import {watch, ref, reactive, computed} from "vue";
const TestObj = ref({
  name:'小红娘',
  age:18,
})

watch(() => TestObj.value.name,(newval,oldval)=>{
  console.log(newval,oldval)
})
setTimeout(() => {
  TestObj.value.name = '小白'
  console.log(11)
}, 2000)
</script>
<template>
  <div>
    123456.吐槽,你不说我怎么知道啊
  </div>
</template>

运行结果如下:

watchEffect

watchEffect,它立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。 也就是说,wactheffect会自动收集函数中的响应式依赖,并且初始化运行一次该函数(相当于watch开启了immediate:true)

举例代码如下:

xml 复制代码
<script setup>
// import {watch, ref, reactive, computed} from "vue";
// const TestObj = ref({
//   name:'小红娘',
//   age:18,
// })
//
// watch(() => TestObj.value.name,(newval,oldval)=>{
//   console.log(newval,oldval)
// })
// setTimeout(() => {
//   TestObj.value.name = '小白'
//   console.log(11)
// }, 2000)

import { ref, reactive, watch, watchEffect } from 'vue';
const single = reactive({ count: 1, test: { a: 1, b: 2 } });
const handleClick = function () {
  single.test.a++;
};
watchEffect(() => {
  console.log('-----', single.test.a);
});

</script>
<template>
  <div>
    <button @click="handleClick">点击</button>
  </div>
</template>

代码初始化运行如下:

当我们点击时如下:

值得注意的是,watcheffect只能获取到最新的值(在函数中直接访问),而不像watch那样可以拿到新值和旧值。

注意:watchEffect在监听数据时,同步函数发生变化时只触发一次监听

代码如下:

xml 复制代码
<template>
  <div class="mine-box">
    <div ref="countDom">{{ single.test.a }}</div>
    <button @click="handleClick">按钮</button>
  </div>
</template>

<script setup>
import { ref, reactive, watch, watchEffect } from 'vue';
const single = reactive({ count: 1, test: { a: 1, b: 2 } });
const countDom = ref(null);
const handleClick = function () {
  single.test.a++;
};
watchEffect(() => {
  console.log(countDom.value);
  console.log('-----', single.test.a);
});
</script>

<style>
.mine-box {
  text-align: center;
}
</style>

当我们点击按钮时,运行效果如下:

可以看到函数只是运行了一次。

watcheffect入参: onInvalidate

onInvalidate在值即将发生改变时发生一次调用

代码如下:

xml 复制代码
<script setup>
import {  reactive,  watchEffect } from 'vue';
const single = reactive({ count: 1, test: { a: 1, b: 2 } });
const handleClick = function () {
  single.test.a++;
};
const stop = watchEffect(onInvalidate => {
  console.log('--监听执行---', single.test.a);
  if (single.test.a > 5) {
    stop();
  }
  onInvalidate(()=>{
    console.log("看好了,我是在属性值发生改变前而触发的")
  })
});

</script>
<style>
.mine-box {
  text-align: center;
}
</style>
<template>
  <div class="mine-box">
    123456
    <button @click="handleClick">按钮</button>
  </div>
</template>

初始化如下:

当我们在点击 按钮时发生如下变化:

销毁监听

watchEffect所在的组件被卸载时 会隐式调用stop函数停止侦听。

通过显示调用返回值停止侦听

ini 复制代码
const stop = watchEffect(onInvalidate => {
  console.log('--监听执行---', single.test.a);
  if (single.test.a > 5) {
    stop();
  }
});
scss 复制代码
const name = ref('小红')

const stop = watch(name, ()=>{
  console.log(name.value)
});

setTimeout(()=>{
  stop()
},1000)
setTimeout(()=>{
  name.value = '111'
  console.log(name)
},2000)

总结:

watchwatchEffect 的主要功能是相同的,都能响应式地执行回调函数。

依赖收集 执行时机 监听对象 返回值
watcheffect 初始化时就收集,并立即执行回调函数 可以没有具体的监听对象 可以没有返回值
watch 初始化时收集,默认当依赖有变更才执行回调函数 必须要有具体的监听对象 有返回值(新值和旧值)
computed 初始化时收集,默认当依赖有变更才执行回调函数 需要具体的对象 返回的是计算属性值(必须有返回)
相关推荐
一斤代码1 小时前
vue3 下载图片(标签内容可转图)
前端·javascript·vue
中微子1 小时前
React Router 源码深度剖析解决面试中的深层次问题
前端·react.js
光影少年1 小时前
从前端转go开发的学习路线
前端·学习·golang
中微子1 小时前
React Router 面试指南:从基础到实战
前端·react.js·前端框架
3Katrina1 小时前
深入理解 useLayoutEffect:解决 UI "闪烁"问题的利器
前端·javascript·面试
前端_学习之路2 小时前
React--Fiber 架构
前端·react.js·架构
伍哥的传说3 小时前
React 实现五子棋人机对战小游戏
前端·javascript·react.js·前端框架·node.js·ecmascript·js
qq_424409193 小时前
uniapp的app项目,某个页面长时间无操作,返回首页
前端·vue.js·uni-app
我在北京coding3 小时前
element el-table渲染二维对象数组
前端·javascript·vue.js
布兰妮甜3 小时前
Vue+ElementUI聊天室开发指南
前端·javascript·vue.js·elementui