xgqfrms™, xgqfrms® : xgqfrms's offical website of cnblogs! xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!

Vue 3 源码学习实现 watchEffect 方法 All in One

Vue 3 源码学习实现 watchEffect 方法 All in One

cleanup

watchEffect(async (onCleanup) => {
  onCleanup(() => {
    console.log('clear');
  });
  console.log(count.value);
})

// 形参 cleanup
watchEffect(async (cleanup) => {
  // 实现形参 cleanup , 没有返回值,怎么执行的 ❓
  cleanup(() => {
    console.log('clear');
  });
  console.log(count.value);
})

源码

  if (isRef(source)) {
    getter = () => source.value
    forceTrigger = isShallow(source)
  } else if (isReactive(source)) {
    getter = () => source
    deep = true
  } else if (isArray(source)) {
    isMultiSource = true
    forceTrigger = source.some(isReactive)
    getter = () =>
      source.map(s => {
        if (isRef(s)) {
          return s.value
        } else if (isReactive(s)) {
          return traverse(s)
        } else if (isFunction(s)) {
          return callWithErrorHandling(s, instance, ErrorCodes.WATCH_GETTER)
        } else {
          __DEV__ && warnInvalidSource(s)
        }
      })
  } else if (isFunction(source)) {
    if (cb) {
      // getter with cb
      getter = () =>
        callWithErrorHandling(source, instance, ErrorCodes.WATCH_GETTER)
    } else {
      // no cb -> simple effect
      getter = () => {
        if (instance && instance.isUnmounted) {
          return
        }
        if (cleanup) {
          cleanup()
        }
        return callWithAsyncErrorHandling(
          source,
          instance,
          ErrorCodes.WATCH_CALLBACK,
          [onCleanup]
        )
      }
    }
  } else {
    getter = NOOP
    __DEV__ && warnInvalidSource(source)
  }

  const job: SchedulerJob = () => {
    if (!effect.active) {
      return
    }
    if (cb) {
      // watch(source, cb)
      const newValue = effect.run()
      if (
        deep ||
        forceTrigger ||
        (isMultiSource
          ? (newValue as any[]).some((v, i) =>
              hasChanged(v, (oldValue as any[])[i])
            )
          : hasChanged(newValue, oldValue)) ||
        (__COMPAT__ &&
          isArray(newValue) &&
          isCompatEnabled(DeprecationTypes.WATCH_ARRAY, instance))
      ) {
        // cleanup before running cb again
        if (cleanup) {
          cleanup()
        }
        callWithAsyncErrorHandling(cb, instance, ErrorCodes.WATCH_CALLBACK, [
          newValue,
          // pass undefined as the old value when it's changed for the first time
          oldValue === INITIAL_WATCHER_VALUE ? undefined : oldValue,
          onCleanup
        ])
        oldValue = newValue
      }
    } else {
      // watchEffect
      effect.run()
    }
  }

https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiWatch.ts#L44

https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiWatch.ts#L240

https://github.com/vuejs/core/blob/main/packages/runtime-core/src/apiWatch.ts#L320

demo

💩 WTF, 为什么 cleanup 参数不需要定义,怎么传递的呀 ?

/*
const cleanup = () => {
  console.log('clear');
}

const onCleanup = () => {
  console.log('clear');
}
*/

// 立即执行一次
// 
💩 WTF, 为什么 cleanup 参数不需要定义,怎么传递的呀 ?
watchEffect(async (cleanup) => {
  // 实现形参, 没有返回值 ?
  cleanup(() => {
    console.log('clear');
  });
  console.log(count.value);
})

Vue 3 源码学习实现 watchEffect 方法

// ???

https://sfc.vuejs.org/

refs

https://vuejs.org/api/reactivity-core.html#watcheffect

https://www.thisdot.co/blog/vue-3-composition-api-watch-and-watcheffect



©xgqfrms 2012-2020

www.cnblogs.com/xgqfrms 发布文章使用:只允许注册用户才可以访问!

原创文章,版权所有©️xgqfrms, 禁止转载 🈲️,侵权必究⚠️!


posted @ 2022-04-03 00:37  xgqfrms  阅读(161)  评论(2编辑  收藏  举报