Skip to content

Commit 409b52a

Browse files
committed
refactor: the watch API with baseWatch
1 parent d8682e8 commit 409b52a

File tree

6 files changed

+147
-262
lines changed

6 files changed

+147
-262
lines changed

packages/reactivity/src/baseWatch.ts

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,16 @@ export interface BaseWatchOptions<Immediate = boolean> extends DebuggerOptions {
6565
deep?: boolean
6666
once?: boolean
6767
scheduler?: Scheduler
68-
handlerError?: HandleError
69-
handlerWarn?: HandleWarn
68+
handleError?: HandleError
69+
handleWarn?: HandleWarn
7070
}
7171

7272
export type WatchStopHandle = () => void
7373

74+
export interface WatchInstance extends WatchStopHandle {
75+
effect?: ReactiveEffect
76+
}
77+
7478
// initial value for watchers to trigger on undefined initial values
7579
const INITIAL_WATCHER_VALUE = {}
7680

@@ -112,20 +116,12 @@ export function baseWatch(
112116
onTrack,
113117
onTrigger,
114118
scheduler = DEFAULT_SCHEDULER,
115-
handlerError = DEFAULT_HANDLE_ERROR,
116-
handlerWarn = warn
119+
handleError: handleError = DEFAULT_HANDLE_ERROR,
120+
handleWarn: handleWarn = warn
117121
}: BaseWatchOptions = EMPTY_OBJ
118-
): WatchStopHandle {
119-
if (cb && once) {
120-
const _cb = cb
121-
cb = (...args) => {
122-
_cb(...args)
123-
unwatch()
124-
}
125-
}
126-
122+
): WatchInstance {
127123
const warnInvalidSource = (s: unknown) => {
128-
handlerWarn(
124+
handleWarn(
129125
`Invalid watch source: `,
130126
s,
131127
`A watch source can only be a getter/effect function, a ref, ` +
@@ -155,7 +151,7 @@ export function baseWatch(
155151
} else if (isFunction(s)) {
156152
return callWithErrorHandling(
157153
s,
158-
handlerError,
154+
handleError,
159155
BaseWatchErrorCodes.WATCH_GETTER
160156
)
161157
} else {
@@ -168,16 +164,12 @@ export function baseWatch(
168164
getter = () =>
169165
callWithErrorHandling(
170166
source,
171-
handlerError,
167+
handleError,
172168
BaseWatchErrorCodes.WATCH_GETTER
173169
)
174170
} else {
175171
// no cb -> simple effect
176172
getter = () => {
177-
// TODO: move to scheduler
178-
// if (instance && instance.isUnmounted) {
179-
// return
180-
// }
181173
if (cleanup) {
182174
cleanup()
183175
}
@@ -186,7 +178,7 @@ export function baseWatch(
186178
try {
187179
return callWithAsyncErrorHandling(
188180
source,
189-
handlerError,
181+
handleError,
190182
BaseWatchErrorCodes.WATCH_CALLBACK,
191183
[onEffectCleanup]
192184
)
@@ -205,29 +197,26 @@ export function baseWatch(
205197
getter = () => traverse(baseGetter())
206198
}
207199

208-
// TODO: support SSR
209-
// in SSR there is no need to setup an actual effect, and it should be noop
210-
// unless it's eager or sync flush
211-
// let ssrCleanup: (() => void)[] | undefined
212-
// if (__SSR__ && isInSSRComponentSetup) {
213-
// // we will also not call the invalidate callback (+ runner is not set up)
214-
// onCleanup = NOOP
215-
// if (!cb) {
216-
// getter()
217-
// } else if (immediate) {
218-
// callWithAsyncErrorHandling(cb, handlerError, BaseWatchErrorCodes.WATCH_CALLBACK, [
219-
// getter(),
220-
// isMultiSource ? [] : undefined,
221-
// onCleanup
222-
// ])
223-
// }
224-
// if (flush === 'sync') {
225-
// const ctx = useSSRContext()!
226-
// ssrCleanup = ctx.__watcherHandles || (ctx.__watcherHandles = [])
227-
// } else {
228-
// return NOOP
229-
// }
230-
// }
200+
if (once) {
201+
if (!cb) {
202+
getter()
203+
return NOOP
204+
}
205+
if (immediate) {
206+
callWithAsyncErrorHandling(
207+
cb,
208+
handleError,
209+
BaseWatchErrorCodes.WATCH_CALLBACK,
210+
[getter(), isMultiSource ? [] : undefined, onEffectCleanup]
211+
)
212+
return NOOP
213+
}
214+
const _cb = cb
215+
cb = (...args) => {
216+
_cb(...args)
217+
unwatch()
218+
}
219+
}
231220

232221
let oldValue: any = isMultiSource
233222
? new Array((source as []).length).fill(INITIAL_WATCHER_VALUE)
@@ -255,7 +244,7 @@ export function baseWatch(
255244
try {
256245
callWithAsyncErrorHandling(
257246
cb,
258-
handlerError,
247+
handleError,
259248
BaseWatchErrorCodes.WATCH_CALLBACK,
260249
[
261250
newValue,
@@ -295,18 +284,21 @@ export function baseWatch(
295284
const cleanup = (effect.onStop = () => {
296285
const cleanups = cleanupMap.get(effect)
297286
if (cleanups) {
298-
cleanups.forEach(cleanup => cleanup())
287+
cleanups.forEach(cleanup =>
288+
callWithErrorHandling(
289+
cleanup,
290+
handleError,
291+
BaseWatchErrorCodes.WATCH_CLEANUP
292+
)
293+
)
299294
cleanupMap.delete(effect)
300295
}
301296
})
302297

303-
const unwatch = () => {
298+
const unwatch: WatchInstance = () => {
304299
effect.stop()
305-
// TODO: move to doWatch
306-
// if (instance && instance.scope) {
307-
// remove(instance.scope.effects!, effect)
308-
// }
309300
}
301+
unwatch.effect = effect
310302

311303
if (__DEV__) {
312304
effect.onTrack = onTrack

packages/reactivity/src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,8 @@ export {
6969
onScopeDispose
7070
} from './effectScope'
7171
export { TrackOpTypes, TriggerOpTypes, ReactiveFlags } from './constants'
72-
export { baseWatch, BaseWatchErrorCodes } from './baseWatch'
72+
export {
73+
baseWatch,
74+
BaseWatchErrorCodes,
75+
type BaseWatchOptions
76+
} from './baseWatch'

0 commit comments

Comments
 (0)