vue3 Computed 与 watch

89 阅读3分钟

computed

  1. 接受一个 getter 函数,并根据 getter 的返回值返回一个不可变的响应式 ref对象。
const count = ref(1)
const plusOne = computed(() => count.value + 1) // 在computed里只有getter函数,就是一个有返回值的函数,
//这样这个值就不能直接修改否则会报错,但是它仍然会跟随count的改变而改变。

console.log(plusOne.value) // 2

plusOne.value++ // 错误
  1. 或者,接受一个具有 get 和 set 函数的对象,用来创建可写的 ref 对象。
const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: val => {
    count.value = val - 1
  }
})

plusOne.value = 1 // 赋值会回调set函数,修改count
console.log(count.value) // 0

watchEffect

立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数。

let numbers = ref(0) 
const stop = watchEffect(()=>{
  console.log(numbers.value); // 开始会打印0,100ms之后打印1
})
setTimeout(()=>{
   numbers.value ++
},100)

在一些情况下,也可以显式调用返回值以停止侦听:

添加这里的代码到上面就可以了,可以把上面的setTimeout改为setInterval,就会发现在1000ms之后就不会在打

印值。
setTimeout(()=>{
   stop()
},1000)

这里需要注意,当一个用户定义的副作用函数进入队列时,默认情况下,会在所有的组件 update前执行:

// 在下面的代码中会发现,dom元素打印为null,获取不到dom元素,这是因为它的执行时机会早于dom的更新。并不能获取带dom,

<div class="numberbox">
   numbers:{{numbers}}
</div>
    
let numbers = ref(0) 
const stop = watchEffect(()=>
  { 
    console.log(document.querySelector('.numberbox'));  // 这里会打印null,
    console.log(numbers.value);
  }
) 

解决办法,1.如果异步更新了numbers的值,就会发现可以获取到dom了,但是在进入时让然没有获取到,也可以添加 如果需要在组件更新后重新运行侦听器副作用,我们可以传递带有 flush选项的附加 options 对象 (默认为 'pre'): flush:有三个值,默认pre,会早于dom更新。post会晚于dom更新。sync,将强制效果始终同步触发。 3.2也可以使用watchPostEffect 和 watchSyncEffect

const stop = watchEffect(()=>
{ 
   console.log(document.querySelector('.numberbox')); // 这样就可以获取到了。
   console.log(numbers.value);
},
{
   flush: 'post'
})

watch

watch 需要侦听特定的数据源,并在回调函数中执行副作用。默认情况下,它也是惰性的,即只有当被侦听的源发生变化时才执行回调。

watch 和 watchEffect 的区别

  1. 懒执行副作用;watch监听的数据发生改变时,才会触发。watchEffect是定义了就会默认执行
  2. 更具体地说明什么状态应该触发侦听器重新运行;
  3. 访问侦听状态变化前后的值。

侦听单个数据源

侦听器数据源可以是返回值的 getter 函数,也可以直接是 ref

let watchnum = ref(0)
watch(
   watchnum,
   (count,precount)=>{
      console.log(count,precount);
   }
)

侦听多个数据源

可以使用数组同时侦听多个源:

const firstName = ref('')
const lastName = ref('')

watch([firstName, lastName], (newValues, prevValues) => {
  console.log(newValues, prevValues)
})

firstName.value = 'John'
lastName.value = 'Smith'  logs: ["John", "Smith"] ["", ""]

注意:如果你在同一个函数里同时改变这些被侦听的来源,侦听器仍只会执行一次。如果是多个同步更改只会触发一次侦听器。上面的代码修改来两次监听数据,但是可以看到它只会触发一次监听。如果想要改变这样的监听,可以进行异步操作来对数据进行修改,也可参口上面的watchEffect的使用,传入第三个参数去修改回调时机。