首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >学习 Vue 3 全家桶 - 响应式机制

学习 Vue 3 全家桶 - 响应式机制

作者头像
Cellinlab
发布2023-05-17 16:50:27
发布2023-05-17 16:50:27
3400
举报
文章被收录于专栏:Cellinlab's BlogCellinlab's Blog

响应式一直都是 Vue 的特色功能之一。

# 响应式原理

Vue 中用过三种响应式解决方案,分别是 defineProperty、Proxy 和 value setter。

# defineProperty

Object.defineProperty() (opens new window) 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

代码语言:javascript
复制
let getDouble = n => n * 2;
let obj = {};
let count = 1;
let double = getDouble(count);

Object.defineProperty(obj, 'count', {
  get: () => count,
  set: value => {
    count = value;
    double = getDouble(count);
  }
});

console.log(double); // 2

obj.count = 2;
console.log(count); // 2
console.log(double); // 4 double 会跟着变化

但 defineProperty API 作为 Vue 2 实现响应式的原理,它的语法中也有一些缺陷。比如在下面代码中,删除 obj.count 属性,set 函数就不会执行,double 还是之前的数值。这也是为什么在 Vue 2 中,需要 $delete 一个专门的函数去删除数据。

代码语言:javascript
复制
delete obj.count;
console.log(double); // 4

# Proxy

Vue 3 的响应式机制是基于 Proxy (opens new window) 实现的,其重要意义在于它解决了 Vue 2 响应式的缺陷。

代码语言:javascript
复制
let proxy = new Proxy(obj, {
  get: function (target, prop) {
    return target[prop];
  },
  set: function (target, prop, value) {
    target[prop] = value;
    if (prop === 'count') {
      double = getDouble(value);
    }
  },
  deleteProperty: function (target, prop) {
    delete target[prop];
    if (prop === 'count') {
      double = NaN;
    }
  }
});

console.log(obj.count, double); // 1 2
proxy.count = 2;
console.log(obj.count, double); // 2 4
delete proxy.count;
console.log(obj.count, double); // undefined NaN

Proxy 是针对对象来监听,而不是针对某个具体属性,所以不仅可以代理那些定义时不存在的属性,还可以代理更丰富的数据结构,比如 Map、Set 等,并且也能通过 deleteProperty 实现对删除操作的代理。

Vue 3 的 reactive 函数可以把一个对象变成响应式数据,而 reactive 就是基于 Proxy 实现的。还可以通过 watchEffect,在 obj.count 修改之后,执行数据的打印。

代码语言:javascript
复制
import { reactive, computed, watchEffect } from 'vue';

let obj = reactive({
  count: 1
});

let double = computed(() => obj.count * 2);

obj.count = 2;

watchEffect(() => {
  console.log('data updated', obj.count, double.value);
});

# value setter

在 Vue 3 中还有另一个响应式实现的逻辑,就是利用对象的 get 和 set 函数来进行监听,这种响应式的实现方式,只能拦截某一个属性的修改,这也是 Vue 3 中 ref 这个 API 的实现。

代码语言:javascript
复制
let getDouble = n => n * 2;
let _value = 1;
double = getDouble(_value);

let count = {
  get value() {
    return _value;
  },
  set value(value) {
    _value = value;
    double = getDouble(_value);
  }
};

console.log(count.value, double); // 1 2
count.value = 2;
console.log(count.value, double); // 2 4

# 三种方法比较

# 响应式应用

让 TodoList 和本地存储同步。

代码语言:javascript
复制
import { ref, computed, watchEffect } from 'vue';

let todolist = ref(JSON.parse(localStorage.getItem('todolist') || '[]'));
watchEffect(() => {
  localStorage.setItem('todolist', JSON.stringify(todolist.value));
});

抽离 useStorage 函数,在响应式的基础之上,把任意数据响应式的变化同步到本地存储。

代码语言:javascript
复制
function useStorage (name, value = []) {
  let data = ref(JSON.parse(localStorage.getItem(name) || value));
  watchEffect(() => {
    localStorage.setItem(name, JSON.stringify(data.value));
  });
  return data;
}

社区也有非常优秀的 Vueuse 工具库,包含了大量类似 useStorage 的工具函数库。

可以把日常开发中用到的数据,无论是浏览器的本地存储,还是网络数据,都封装成响应式数据,统一使用响应式数据开发的模式。这样,开发项目的时候,只需要修改对应的数据就可以了。

# Vueuse

VueUse (opens new window) 趁着这一波 Vue 3 的更新,跟上了响应式 API 的潮流。VueUse 的官方的介绍说这是一个 Composition API 的工具集合,适用于 Vue 2.x 或者 Vue 3.x,用起来和 React Hooks 很像。

代码语言:javascript
复制
# 安装
npm install @vueuse/core

VueUse 中包含了很多常用的工具函数,可以把网络状态、异步请求的数据、动画和事件等功能,都看成是响应式的数据去管理。

代码语言:javascript
复制
<template>
  <h1 @click="toggle">toggle</h1>
</template>

<script setup>
import { useFullscreen } from '@vueuse/core';

const { isFullscreen, enter, exit, toggle } = useFullscreen();
</script>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022/2/3,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 响应式原理
    • # defineProperty
    • # Proxy
    • # value setter
    • # 三种方法比较
  • # 响应式应用
  • # Vueuse
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档