rimochiko / nichijio-notes

记录一些有的没的
0 stars 0 forks source link

Vue 3 - 数据侦测 #9

Open rimochiko opened 4 years ago

rimochiko commented 4 years ago

Vue 2的做法

  1. getter、setter
  2. defineProperty

缺点:

  1. 无法感知数组的变化。(只对特定方法进行了处理)
  2. push() pop() shift() unshift() splice() sort() reverse()

Vue 3-Proxy API

Proxy:用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。 traps:提供属性访问的方法。这类似于操作系统中捕获器的概念。 Object|Array|Map|Set|WeakMap|WeakSet https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

直接用会有问题

多次调用

let data = [1,2,3] 
let p = new Proxy(data, { 
    get(target, key, receiver) { 
        return target[key]
  },
  set(target, key, value, receiver) {
      console.log(‘set value’) 
      target[key] = value 
      return true  // 不加会报错,why?
  } 
}) 
p.push(4)

// get value: push // get value: length // set value: 3 1 // set value: length 4

p.push(1)

可以通过Reflect来返回 trap 相应的默认行为

解决 setTimeout 解决重复 trigger

set(target, key, value, receiver) { 
    clearTimeout(timer) 
    timer = setTimeout(() => { cb && cb() }, 0); 
    return Reflect.set(target, key, value, receiver) 
}

trap只能代理一层

p.bar.key = 2 // get value: bar

对于 receiver ,其实接收的是一个代理对象:// { a: {b: {c: 1 } } } 会返回内部a的对象;

解决: 递归代理

for (let key in data) { 
    if (typeof data[key] === 'object') { 
       res[key] = reactive(data[key], cb) 
    } else { 
       res[key] = data[key] 
    } 
}

reactive.ts rawToReactive# 和 reactiveToRaw# 是两个弱引用的 Map# 结构,这两个 Map# 用来保存 原始数据# 和 可响应数据

判断 key 是否为 target 自身属性,以及设置val是否跟target[key]相等