Skip to content

Commit

Permalink
feat!: useEffect
Browse files Browse the repository at this point in the history
  • Loading branch information
Mitscherlich committed Dec 27, 2022
1 parent ab70d1b commit 9a71ad4
Showing 1 changed file with 71 additions and 33 deletions.
104 changes: 71 additions & 33 deletions packages/vhooks/src/useEffect/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,20 @@ import type {
DependencyList,
EffectCallback,
} from '@m9ch/vhooks-types'
import { toArray } from '@m9ch/utils'
import {
getCurrentScope,
isArray,
isMap,
isObject,
isPlainObject,
isSet,
} from '@m9ch/vhooks-utils'
import {
effect,
getCurrentInstance,
isReactive,
isRef,
onScopeDispose,
onUpdated,
queuePostFlushCb,
shallowRef,
watch,
} from 'vue-demi'
import type { Cleanup, Effect } from './types'

Expand All @@ -24,47 +29,80 @@ export default function useEffect(fn: EffectCallback, deps?: DependencyList) {
invokeCleanup.current = null
}
}

const invokeEffect: Effect = () => {
const { current } = invokeEffect
if (current) {
invokeCleanup.current = current()
invokeEffect.current = fn
}
}

invokeEffect.current = fn

let source: DependencyList
if (!deps)
source = []
else if (deps.some(dep => !isRef(dep) && !isReactive(dep)))
source = toArray(deps).map(dep => !isRef(dep) && !isReactive(dep) ? shallowRef(dep) : dep)
else
source = toArray(deps)
const job = () => {
invokeCleanup()
invokeEffect()
}
const visitor = (dep: any) => {
if (Array.isArray(dep))
return dep.map(visitor)
if (isReactive(dep))
return traverse(dep)
if (isRef(dep))
return dep.value
return dep
}
effect(() => visitor(deps), {
scheduler: job,
onStop: invokeCleanup,
})
mountEffect()
updateEffect()

const stopWatch = watch(source, (newArgs, oldArgs) => {
if (argsChanged(oldArgs, newArgs)) {
invokeCleanup()
invokeEffect()
function mountEffect() {
queuePostRenderEffect(job)
}
function updateEffect() {
if (!deps && getCurrentInstance()) {
// make sure there is a vm instance
onUpdated(() => {
queuePostFlushCb(job)
})
}
}, { flush: 'post', deep: true })

queuePostRenderEffect(invokeEffect)

const stop = () => {
stopWatch()
invokeCleanup()
}
}

if (getCurrentScope())
onScopeDispose(stop)
export enum ReactiveFlags {
SKIP = '__v_skip',
IS_REACTIVE = '__v_isReactive',
IS_READONLY = '__v_isReadonly',
IS_SHALLOW = '__v_isShallow',
RAW = '__v_raw',
}

function argsChanged(oldArgs: any[], newArgs: any[]) {
return (
!oldArgs
|| oldArgs.length !== newArgs.length
|| oldArgs.some((arg, index) => arg !== newArgs[index])
)
export function traverse(value: unknown, seen?: Set<unknown>) {
if (!isObject(value) || (value as any)[ReactiveFlags.SKIP])
return value

seen = seen || new Set()
if (seen.has(value))
return value

seen.add(value)
if (isRef(value)) {
traverse(value.value, seen)
}
else if (isArray(value)) {
for (let i = 0; i < value.length; i++)
traverse(value[i], seen)
}
else if (isSet(value) || isMap(value)) {
value.forEach((v: any) => {
traverse(v, seen)
})
}
else if (isPlainObject(value)) {
for (const key in value)
traverse((value as any)[key], seen)
}
return value
}

0 comments on commit 9a71ad4

Please sign in to comment.