Skip to content

Commit

Permalink
feat(runtime-core, reactivity): baseWatch + onWatcherCleanup
Browse files Browse the repository at this point in the history
Squashed commit of the following:

commit dad9d0f
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Mar 14 20:35:19 2024 +0800

    feat: scheduler in reactivity

commit 406c750
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Mar 14 14:08:12 2024 +0800

    fix: revert export alias

commit 74996b6
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Wed Mar 13 22:21:27 2024 +0800

    test: onWatcherCleanup in apiWatch

commit a5769e1
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Wed Mar 13 22:09:43 2024 +0800

    fix: remove elusive code for once

commit 589cd11
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Wed Mar 13 21:14:34 2024 +0800

    fix: errors related to immediateFirstRun

commit 3694745
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Tue Mar 12 18:16:52 2024 +0800

    refactor: rename to onWatcherCleanup, getCurrentWatcher, remove middleware

commit b3f45d2
Merge: 60a1b97 9a936aa
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Mar 7 22:23:13 2024 +0800

    chore: merge branch 'minor' into feat/onEffectCleanup-and-baseWatch

commit 60a1b97
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Tue Jan 9 20:45:31 2024 +0800

    feat: middleware in baseWatch

commit 2fdda65
Merge: 39f07cd 2701355
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Mon Jan 8 17:40:54 2024 +0800

    Merge branch 'main' into feat/onEffectCleanup-and-baseWatch

commit 39f07cd
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Mon Jan 8 17:40:18 2024 +0800

    fix: should export getCurrentEffect function

commit 770c21d
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Sat Jan 6 00:07:41 2024 +0800

    fix: sync code changes according to the review in PR vuejs/vue-vapor#82

commit a6eb043
Merge: 8dd0c1f 0275dd3
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Fri Jan 5 23:43:02 2024 +0800

    chore: merge branch 'main' into feat/onEffectCleanup-and-baseWatch

commit 8dd0c1f
Merge: 2213634 274f6f7
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Sun Dec 31 20:30:29 2023 +0800

    chore: merge remote-tracking branch 'origin/minor' into feat/onEffectCleanup-and-baseWatch

commit 2213634
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Sun Dec 31 19:21:12 2023 +0800

    refactor: simplify unwatch implementation

commit f44ef0b
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Sun Dec 31 18:45:04 2023 +0800

    feat: implement getCurrentEffect

commit a078ad1
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Dec 28 21:28:28 2023 +0800

    chore: rename handleWarn to onWarn

commit 90fd005
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Dec 28 21:05:03 2023 +0800

    chore: organize exports

commit e9555ce
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Dec 28 20:36:56 2023 +0800

    test: baseWatch

commit d99e9a6
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Dec 28 20:04:42 2023 +0800

    test: onEffectCleanup in runtime-core

commit 56c87ec
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Dec 28 19:44:43 2023 +0800

    test: baseWatch with onEffectCleanup

commit 7c5f05a
Merge: a8dc8e6 75dbbb8
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Thu Dec 28 17:32:00 2023 +0800

    Merge branch 'minor' of https://github.com/vuejs/core into feat/onEffectCleanup-and-baseWatch

commit a8dc8e6
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Wed Dec 27 22:43:17 2023 +0800

    fix: tracked in cleanup

commit b57405c
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Wed Dec 27 20:28:49 2023 +0800

    fix: treeshaking error

commit 4d04f5e
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Wed Dec 27 20:19:53 2023 +0800

    fix: treeshaking error

commit d1f001b
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Wed Dec 27 20:10:05 2023 +0800

    fix: lint

commit 97179ed
Merge: 2aef609 9183069
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Tue Dec 26 23:24:47 2023 +0800

    chore: merge branch 'minor' of https://github.com/vuejs/core into feat/onEffectCleanup-and-baseWatch

commit 2aef609
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Tue Dec 26 22:19:26 2023 +0800

    fix: some cases for server-renderer

commit db4463c
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Tue Dec 26 21:40:12 2023 +0800

    fix: export onEffectCleanup

commit 409b52a
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Tue Dec 26 21:31:27 2023 +0800

    refactor: the watch API with baseWatch

commit d8682e8
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Mon Dec 25 22:09:38 2023 +0800

    feat: initial code of baseWatch

commit f1fe01e
Author: Rizumu Ayaka <rizumu@ayaka.moe>
Date:   Mon Dec 25 20:50:35 2023 +0800

    refactor: externalized COMPAT case
  • Loading branch information
LittleSound committed Aug 9, 2024
1 parent cffe866 commit 1730ab4
Show file tree
Hide file tree
Showing 14 changed files with 800 additions and 331 deletions.
183 changes: 183 additions & 0 deletions packages/reactivity/__tests__/baseWatch.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import {
BaseWatchErrorCodes,
EffectScope,
type Ref,
type SchedulerJob,
type WatchScheduler,
baseWatch,
onWatcherCleanup,
ref,
} from '../src'

const queue: SchedulerJob[] = []

// these codes are a simple scheduler
let isFlushPending = false
const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise<any>
const nextTick = (fn?: () => any) =>
fn ? resolvedPromise.then(fn) : resolvedPromise
const scheduler: WatchScheduler = (job, effect, immediateFirstRun, hasCb) => {
if (immediateFirstRun) {
!hasCb && effect.run()
} else {
queue.push(() => job(immediateFirstRun))
flushJobs()
}
}
const flushJobs = () => {
if (isFlushPending) return
isFlushPending = true
resolvedPromise.then(() => {
queue.forEach(job => job())
queue.length = 0
isFlushPending = false
})
}

describe('baseWatch', () => {
test('effect', () => {
let dummy: any
const source = ref(0)
baseWatch(() => {
dummy = source.value
})
expect(dummy).toBe(0)
source.value++
expect(dummy).toBe(1)
})

test('watch', () => {
let dummy: any
const source = ref(0)
baseWatch(source, () => {
dummy = source.value
})
expect(dummy).toBe(undefined)
source.value++
expect(dummy).toBe(1)
})

test('custom error handler', () => {
const onError = vi.fn()

baseWatch(
() => {
throw 'oops in effect'
},
null,
{ onError },
)

const source = ref(0)
const effect = baseWatch(
source,
() => {
onWatcherCleanup(() => {
throw 'oops in cleanup'
})
throw 'oops in watch'
},
{ onError },
)

expect(onError.mock.calls.length).toBe(1)
expect(onError.mock.calls[0]).toMatchObject([
'oops in effect',
BaseWatchErrorCodes.WATCH_CALLBACK,
])

source.value++
expect(onError.mock.calls.length).toBe(2)
expect(onError.mock.calls[1]).toMatchObject([
'oops in watch',
BaseWatchErrorCodes.WATCH_CALLBACK,
])

effect!.stop()
source.value++
expect(onError.mock.calls.length).toBe(3)
expect(onError.mock.calls[2]).toMatchObject([
'oops in cleanup',
BaseWatchErrorCodes.WATCH_CLEANUP,
])
})

test('baseWatch with onEffectCleanup', async () => {
let dummy = 0
let source: Ref<number>
const scope = new EffectScope()

scope.run(() => {
source = ref(0)
baseWatch(onCleanup => {
source.value

onCleanup(() => (dummy += 2))
onWatcherCleanup(() => (dummy += 3))
onWatcherCleanup(() => (dummy += 5))
})
})
expect(dummy).toBe(0)

scope.run(() => {
source.value++
})
expect(dummy).toBe(10)

scope.run(() => {
source.value++
})
expect(dummy).toBe(20)

scope.stop()
expect(dummy).toBe(30)
})

test('nested calls to baseWatch and onEffectCleanup', async () => {
let calls: string[] = []
let source: Ref<number>
let copyist: Ref<number>
const scope = new EffectScope()

scope.run(() => {
source = ref(0)
copyist = ref(0)
// sync by default
baseWatch(
() => {
const current = (copyist.value = source.value)
onWatcherCleanup(() => calls.push(`sync ${current}`))
},
null,
{},
)
// with scheduler
baseWatch(
() => {
const current = copyist.value
onWatcherCleanup(() => calls.push(`post ${current}`))
},
null,
{ scheduler },
)
})

await nextTick()
expect(calls).toEqual([])

scope.run(() => source.value++)
expect(calls).toEqual(['sync 0'])
await nextTick()
expect(calls).toEqual(['sync 0', 'post 0'])
calls.length = 0

scope.run(() => source.value++)
expect(calls).toEqual(['sync 1'])
await nextTick()
expect(calls).toEqual(['sync 1', 'post 1'])
calls.length = 0

scope.stop()
expect(calls).toEqual(['sync 2', 'post 2'])
})
})
Loading

0 comments on commit 1730ab4

Please sign in to comment.