Pl Vue

响应式数据

reactive

reactive 是进行数据监听核心,所有响应式数据都是建立在 reactive 的基础上。

const obj = reactive({
  a: 0,
});
obj.a++;

ref

与 reactive 一样,使用时通过 .value 访问。

const count = ref(0);
count.value++;

customRef

自定义 ref:对数据更新做控制。比如下面是一个去除空格的例子

const str = removeSpaceRef('');
str.value = ' hello ';  //--> 'hello'

function removeSpaceRef(value: string) {
  return customRef((track, trigger) => ({
    get() {
      track();  // 收集依赖
      return value;
    },
    set(val) {
      value = val.trim();
      trigger();  // 派发更新
    }
  }))
}

computed

计算属性:接收一个响应式数据,返回一个新的响应式数据(只读)。同样通过 .value 访问。

const a = ref(0);
const b = computed(() => a.value);
a.value++;  // a 发生变化,b 也会自动更新
console.log(b.value);  //--> 1
const a = ref(0);
computed({
  get: () => a.value,
  set(val) {
    // a 被重新赋值时执行
    // code...
  }
});

binding

binding 是实现数据更新的核心,当 binding 使用了响应式数据(具体的值,而不是一个对象),该值发生变化,绑定的函数也会重新执行。

正因为函数中用到了响应式数据,所以 reactive 也就是 proxy.get 才能监听到,将此函数进行收集,保存在执行队列中。 为了节省内存空间,在绑定的函数返回 true 时,该函数将会执行队列中的任务进行删除. 当然,dom 的自动更新同样用到了 binding

const count = ref(0);

binding(() => {  // 数据发生改变,函数即执行
  console.log(count.value);
})

watchEffect

watchEffect 基于 binding 实现,因为 binding 本身就可以作为一个监听函数使用。在用法上与 vue watchEffect 一致。

const count = ref(0);

watchEffect(() => {  // 数据发生改变,函数即执行
  console.log(count.value);
})

watchEffect 与 binding 的区别:

  1. binding 可以监听整个对象,对象中的任意一个值发生变化都会触发更新;而 watchEffect 只监听用到的值;

watch

watch 基于 binding 实现,因为 binding 本身就可以作为一个监听函数使用。watch 在此基础上加了一个额外的配置参数。 在用法上与 vue watch 一致。

与 vue watch 的差异:

  1. 监听目标只能以一个函数形式形式传递
  2. 当 watch 监听目标为一个引用值时,其中回调的第二个参数 oldValue,plvue 返回的是一个非响应式旧数据。而在 vue 中返回的是该数据本身,作者认为这里返回数据本身并没有什么意义
const o = reactive({
  a: 1,
  b: 2,
})

const unwatch = watch(
  () => o,
  (value, oldValue) => {
    // value !== oldValue 
    // code...
  },
  {
    immediate: true,  // 是否立即执行
    deep: true,       // 开启深度监听
  }
)

binding 和 watch 的区别:

  1. binding 在用到对象中的某个 key 时触发更新,监听的是整个对象;
  2. binding 不能够进行深度监听,watch 可以;
const o = reactive({
  a: 0,
  b: 1,
  c: {
    d: 2,
  },
})

binding(() => {
  o.a;  // o['a'|'b'|'c'] 发生变化时更新
})
binding(() => {
  o.c.d;  // o.a 发生变换时不会触发,因为这里监听的是 o.c 这个对象
})

watch(() => o.a, value => {
  // o.a 发生变化时执行
})
watch(() => o, value => {
  // o 中的任何一个值发生变化即执行
}, { deep: true })