**开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情 响应式数据的基本实现
实现响应式系统--解决非响应属性更改造成的多余更新。
问题 改变obj中非响应式内容时候obj.other = 'hello vue'执行了副用用函数
obj.other = 'hello vue'改变的时候,我们用到的只有text 所以text变化才更改,否则造成了过度渲染性能浪费,上一节中我们遇到了,非响应式数据改变结果 副用用函数也执行了。
如何实现
因为这个问题跟obj中的key有关,很容易联想到我们存的时候把响应式的key和副作用函数关联起来不就可以了吗
即
key: effectFunc
最终数据格式即如下
{target1: { key: {function}} }}
所以在obj.text的时候我们拦截get方法,构建上面格式的数据结构
let keyMap = effectFuncList.get(target)
if (!keyMap) effectFuncList.set(target, (keyMap = new Map()))
let deps = keyMap.get(key)
if (!deps) keyMap.set(key, (deps = new Set()))
// 收集依赖方法(副作用函数)
deps.add(activeEffect)
注意前两层是map最后方法的对象是set。set和map的区别是set中的值不重复且只存key不保存value的对象。
// html.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>响应式数据</title>
</head>
<body>
</body>
// 引入我们写的js代码
<script type="text/javascript" src="./index2.js"></script>
</html>
//index2.js
// 用来保存响应式函数
let activeEffect
function effect(fn) {
activeEffect = fn
fn()
}
//---------响应式数据相关------------
let effectFuncList = new WeakMap()
const data = { text: 'hello world' }
// vue3 用的Proxy
const obj = new Proxy(data, {
get(target, key) {
if (!activeEffect) return target[key]
// 是不是根据key来保存就能够保证唯一呢。
let keyMap = effectFuncList.get(target)
if (!keyMap) effectFuncList.set(target, (keyMap = new Map()))
let deps = keyMap.get(key)
if (!deps) keyMap.set(key, (deps = new Set()))
// 收集依赖方法(副作用函数)
deps.add(activeEffect)
return target[key]
},
set(target, key, newValue) {
target[key] = newValue
// 根据target获取以key为键的集合
const keyMap = effectFuncList.get(target)
if (!keyMap) return
// 根据target获取以key为键的集合
const effectsSet = keyMap.get(key)
if (!effectsSet) return
// 执行副作用函数
effectsSet && effectsSet.forEach(fn => fn())
}
})
//--------------------------
// 调用effect函数将,第一个参数即改变innerText的函数即副作用函数
effect(() => {
console.warn('副用用函数执行====')
document.body.innerText = obj.text
})
// 2秒后改变obj.other的值
setTimeout(() => {
obj.other = 'hello vue'
}, 2000);
最终发现控制台 console.warn('副用用函数执行====')只打印了一次
扩展:
- 必须用Map来保存吗,可以用Object吗,Object和map有什么区别?
这里只能用map,因为例子里面有大量修改删除等操作,并且target是对象,对象作为key只能是map。对于二者区别可以参考
- 为什么target对象的时候用的是WeakMap可以用map吗两者有什么区别?
因为当obj对象销毁的时候,weakmap可以方便回收。
完成。
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情 响应式数据的基本实现