【Vue3.0】- 计算属性

2020-11-25  本文已影响0人  啦啦啦喽啰

计算属性

计算属性 API: computed

例子

import { computed, ref } from 'vue' 
const count = ref(1) 
const result = computed(() => count.value + 1) 
console.log(result.value) // 2 
result.value++ // error 
count.value++ 
console.log(result.value) // 3
const result = computed({ 
  get: () => count.value + 1, 
  set: val => { 
    count.value = val - 1 
  } 
}) 

computed API 的实现

function computed(getterOrOptions) { 
  // getter 函数 
  let getter 
  // setter 函数 
  let setter 
  // 标准化参数 
  if (isFunction(getterOrOptions)) { 
    // 表面传入的是 getter 函数,不能修改计算属性的值 
    getter = getterOrOptions 
    setter = (process.env.NODE_ENV !== 'production') 
      ? () => { 
        console.warn('Write operation failed: computed value is readonly') 
      } 
      : NOOP 
  } 
  else { 
    getter = getterOrOptions.get 
    setter = getterOrOptions.set 
  } 
  // 数据是否脏的 
  let dirty = true 
  // 计算结果 
  let value 
  let computed 
  // 创建副作用函数 
  const runner = effect(getter, { 
    // 延时执行 
    lazy: true, 
    // 标记这是一个 computed effect 用于在 trigger 阶段的优先级排序 
    computed: true, 
    // 调度执行的实现 
    scheduler: () => { 
      if (!dirty) { 
        dirty = true 
        // 派发通知,通知运行访问该计算属性的 activeEffect 
        trigger(computed, "set" /* SET */, 'value') 
      } 
    } 
  }) 
  // 创建 computed 对象 
  computed = { 
    __v_isRef: true, 
    // 暴露 effect 对象以便计算属性可以停止计算 
    effect: runner, 
    get value() { 
      // 计算属性的 getter 
      if (dirty) { 
        // 只有数据为脏的时候才会重新计算 
        value = runner() 
        dirty = false 
      } 
      // 依赖收集,收集运行访问该计算属性的 activeEffect 
      track(computed, "get" /* GET */, 'value') 
      return value 
    }, 
    set value(newValue) { 
      // 计算属性的 setter 
      setter(newValue) 
    } 
  } 
  return computed 
}

计算属性的运行机制

get value() { 
  // 计算属性的 getter 
  if (dirty) { 
    // 只有数据为脏的时候才会重新计算 
    value = runner() 
    dirty = false 
  } 
  // 依赖收集,收集运行访问该计算属性的 activeEffect 
  track(computed, "get" /* GET */, 'value') 
  return value 
}
const run = (effect) => { 
  // 调度执行 
  if (effect.options.scheduler) { 
    effect.options.scheduler(effect) 
  } 
  else { 
    // 直接运行 
    effect() 
  } 
}
scheduler: () => { 
  if (!dirty) { 
    dirty = true 
    // 派发通知,通知运行访问该计算属性的 activeEffect 
    trigger(computed, "set" /* SET */, 'value') 
  } 
}

Computed 计算属性两个特点

Computed 的优势

只要依赖不变化,就可以使用缓存的 value 而不用每次在渲染组件的时候都执行函数去计算

嵌套计算属性

计算属性中访问另外一个计算属性

const count = ref(0) 
const result1 = computed(() => { 
  return count.value + 1 
}) 
const result2 = computed(() => { 
  return result1.value + 1 
}) 
console.log(result2.value)

计算属性的执行顺序

const add = (effectsToAdd) => { 
  if (effectsToAdd) { 
    effectsToAdd.forEach(effect => { 
      if (effect !== activeEffect || !shouldTrack) { 
        if (effect.options.computed) { 
          computedRunners.add(effect) 
        } 
        else { 
          effects.add(effect) 
        } 
      } 
    }) 
  } 
} 
const run = (effect) => { 
  if (effect.options.scheduler) { 
    effect.options.scheduler(effect) 
  } 
  else { 
    effect() 
  } 
} 
computedRunners.forEach(run) 
effects.forEach(run)

为什么computed runner执行优先于普通的effect函数?

上一篇 下一篇

猜你喜欢

热点阅读