SOURCE

console 命令行工具 X clear

                    
>
console
// 用于收集依赖
const bucket = new WeakMap()
// 创建一个记录副作用函数的栈
const effectStack = []
// 创建一个中间值去记录effect函数
let activeEffect

const effect = function (fn) {
    const effectFn = () => {
        cleanUp(effectFn)
        activeEffect = effectFn
        // 入栈
        effectStack.push(effectFn)
        fn()

        // 出栈
        effectStack.pop()
        activeEffect = effectStack[effectStack.length - 1]
    }

    // 用来存储那些依赖集合包含的副作用函数
    effectFn.deps = []
    // 第一次必须执行一遍
    effectFn()
    // console.log(effectStack.length, '---')
}

function cleanUp(effectFn) {
    for (let i = 0; i < effectFn.deps.length; i++) {
        const deps = effectFn.deps[i]
        deps.delete(effectFn)
    }
    effectFn.deps.length = 0
}

// 设计追踪函数
function trackFunc(target, key) {
    // 如果当前activeEffect是空的,说明无法收集依赖
    if (!activeEffect) {
        return
    }

    // 每一个target在bucket中都有一个Map类型,去记录我当前的变量的key对应的effect函数
    let depsMap = bucket.get(target)
    if (!depsMap) {
        // 如果没有就创建新的
        bucket.set(target, (depsMap = new Map()))
    }
    // 创建完成后去找对应的key存储的effect函数
    let deps = depsMap.get(key)
    // 如果没有呢,就继续创建
    if (!deps) {
        depsMap.set(key, (deps = new Set()))
    }
    // 将当前激活的effect函数存储进去
    deps.add(activeEffect)
}

// 执行依赖,也就是在变量赋值后执行effect函数
function trigger(target, key) {
    // 读取depsMap
    const depsMap = bucket.get(target)
    if (!depsMap) {
        return
    }
    let deps = depsMap.get(key)

    if (deps) {
        deps = new Set(deps)
        deps.forEach(fn => fn())
    }
}

// reactive的实现就很简单了
function reactive(data) {
    return new Proxy(data, {
        get: (target, key) => {
            const value = target[key]
            trackFunc(target, key)

            return value
        },
        set: (target, key, newValue) => {
            target[key] = newValue
            trigger(target, key)
        }
    })
}

// const state = reactive({
//   ok: true,
//   text: 'hello world',
// });

// effect(() => {
//   console.log('渲染执行')
//   document.querySelector('#app').innerHTML = state.ok ? state.text : 'not'
// })



// setTimeout(() => {
//   state.ok = false // 此时页面变成了not

//   setTimeout(() => {
//     state.text = 'other' // 页面依然是not,但是副作用函数却还会执行一次
//   }, 1000)
// }, 1000)



// const state = reactive({
//     ok: true,
//     text: 'hello world',
// });

// effect(() => {
//     console.log('渲染执行')
//     document.querySelector('#app').innerHTML = state.ok ? state.text : 'not'
// })

// setTimeout(() => {
//     state.ok = false // 页面渲染为not

//     setTimeout(() => {
//         state.text = 'other' // 页面依然是not,但是副作用函数不会再执行。
//     }, 3000)
// }, 1000)



const state2 = reactive({
  foo: true,
  bar: true
})

effect(function effectFn1 () {
  console.log('effectFn1-----------***************')

  effect(function effectFn2 () {
    console.log('effectFn2--------//////////////')
    console.log('Bar----------', state2.bar)
  })
  
  console.log('Foo------', state2.foo)
})

setTimeout(() => {
  state2.foo = false
}, 5000)
<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="UTF-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<title>Document</title>
</head>

<body>
	<div id="app"></div>
</body>

</html>
#app{
    width: 200px;
    height: 100px;
    background-color: #ffffff;
}