响应性基础

152 阅读3分钟

响应性是指数据的修改会自动同步更新视图效果。其中也包括其他的数据同步,比如computed、watch、vuex等,但数据的同步不一定就是具有响应性,体现响应性的效果最终应该回到数据的更新会自动更新视图这点上,这个自动过程是因为框架实现了MVVM模型的VM,原本是MVC,也就是VM看作C,获取数据并操作视图这些大量繁琐过程自动化了,从而减少开发操作DOM的工作量。

Vue3

ref

示例一

简单了解一下概念的来源,然后了解基础用法,这里使用Vue3作为示例代码。

来看一段奇怪的代码:

<script setup>
  import {ref} from 'vue';

  let count = ref(0);
  let total = 0;

  function onAddClick() {
    count.value++;
    total++;
  }
</script>

<template>
  <div>count:{{ count }}</div>
  <div>total:{{ total }}</div>
  <button @click="onAddClick">+</button>
</template>

当点击+按钮的时候,发现在视图上不仅count更新了,total也更新了,这里是因为count是响应性变量,count的修改触发视图的更新,而视图的更新以一个Vue组件为单位进行更新,所以total视图也更新了。所以在开发中有时会出现非响应性变量也能更新,有时误以为这个变量也具有响应性。

从这个例子知道,一个变量在视图的更新了但这个变量可能并非是响应性变量,在实际开发中会更复杂一些,需要知道数据的修改会不会触发视图更新,因为把非响应性变量当做响应性变量会出现视图未更新的情况。但有一点能确定的是,响应性变量的修改最终和模板关联,那么就会以这个组件单位更新视图。而如果组件内定义了响应性变量但没和模板关联,那么并不会触发视图更新。比如以下代码:

<script setup>
  import {ref} from 'vue';

  let count = ref(0);
  let total = 0;

  function onAddClick() {
    count.value++;
    total++;
  }
</script>

<template>
<!--  <div>count:{{ count }}</div>-->
  <div>total:{{ total }}</div>
  <button @click="onAddClick">+</button>
</template>

示例二

来看一下这段代码的打印结果:

<script setup>
  import {ref} from 'vue';

  let count = ref(0);

  function onAddClick() {
    count.value++;
    console.log('count', count)
    console.log('count value', count.value)
  }
</script>

<template>
  <div>count:{{ count }}</div>
  <button @click="onAddClick">+</button>
</template>

image.png

可以看到count变量是通过RefImpl new出来的,实际的值在value属性上。

computed

<script setup>
  import {computed, ref} from 'vue';

  let count = ref(0);

  const total = computed(() => {
    return count.value + 1;
  })

  function onAddClick() {
    count.value++;
  }
</script>

<template>
  <div>count:{{ count }}</div>
  <div>total:{{ total }}</div>
  <button @click="onAddClick">+</button>
</template>

这段代码中的total是正常触发视图更新,而下面这段代码并不会:

<script setup>
  import {computed, ref} from 'vue';

  let count = ref(0);
  let pureCount = 0;

  const total = computed(() => {
    return pureCount + 1;
  })

  function onAddClick() {
    pureCount++;
  }
</script>

<template>
  <div>count:{{ count }}</div>
  <div>total:{{ total }}</div>
  <button @click="onAddClick">+</button>
</template>

total是Ref类型,当依赖的响应性变量值修改了,会触发重新计算,而method是当视图更新了就会触发。

watch

<script setup>
const x = ref(0);
const y = ref(0) 
// 单个 ref 
watch(x, (newX) => { console.log(`x is ${newX}`) }) 
// getter 函数 
watch( () => x.value + y.value, (sum) => { 
  console.log(`sum of x + y is: ${sum}`) 
}) 
// 多个来源组成的数组 
watch([x, () => y.value], ([newX, newY]) => { 
  console.log(`x is ${newX} and y is ${newY}`) 
})
</script>

hook

官方文档对hook的介绍:cn.vuejs.org/guide/reusa…

hook函数也叫做组合式函数,和函数相比的区别在于hook函数是有状态的复用。这里的有状态、无状态是什么意思呢?

  • 无状态:是指每次调用函数,前一次的调用后不会影响下一次的调用,每次调用的效果是相互独立的
  • 有状态:可能调用的效果会相互影响 hook函数通常是有状态的,hook函数通常也是有副作用的,这点官方文档没有说明,有副作用是指如果不了解hook所依赖的状态及转换是怎样的,可能会有意外的效果。

大部分的hook函数功能通过普通函数也可以实现,但在和框架的结合程度上不如hook函数。hook函数的目的是为了在框架上更简洁而设计的函数。