Skip to content

Commit 60a1b97

Browse files
committed
feat: middleware in baseWatch
1 parent 2fdda65 commit 60a1b97

File tree

3 files changed

+117
-24
lines changed

3 files changed

+117
-24
lines changed

packages/reactivity/__tests__/baseWatch.spec.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,4 +175,82 @@ describe('baseWatch', () => {
175175
scope.stop()
176176
expect(calls).toEqual(['sync 2', 'post 2'])
177177
})
178+
test('baseWatch with middleware', async () => {
179+
let effectCalls: string[] = []
180+
let watchCalls: string[] = []
181+
const source = ref(0)
182+
183+
// effect
184+
baseWatch(
185+
() => {
186+
source.value
187+
effectCalls.push('effect')
188+
onEffectCleanup(() => effectCalls.push('effect cleanup'))
189+
},
190+
null,
191+
{
192+
scheduler,
193+
middleware: next => {
194+
effectCalls.push('before effect running')
195+
next()
196+
effectCalls.push('effect ran')
197+
},
198+
},
199+
)
200+
// watch
201+
baseWatch(
202+
() => source.value,
203+
() => {
204+
watchCalls.push('watch')
205+
onEffectCleanup(() => watchCalls.push('watch cleanup'))
206+
},
207+
{
208+
scheduler,
209+
middleware: next => {
210+
watchCalls.push('before watch running')
211+
next()
212+
watchCalls.push('watch ran')
213+
},
214+
},
215+
)
216+
217+
expect(effectCalls).toEqual([])
218+
expect(watchCalls).toEqual([])
219+
await nextTick()
220+
expect(effectCalls).toEqual([
221+
'before effect running',
222+
'effect',
223+
'effect ran',
224+
])
225+
expect(watchCalls).toEqual([])
226+
effectCalls.length = 0
227+
watchCalls.length = 0
228+
229+
source.value++
230+
await nextTick()
231+
expect(effectCalls).toEqual([
232+
'before effect running',
233+
'effect cleanup',
234+
'effect',
235+
'effect ran',
236+
])
237+
expect(watchCalls).toEqual(['before watch running', 'watch', 'watch ran'])
238+
effectCalls.length = 0
239+
watchCalls.length = 0
240+
241+
source.value++
242+
await nextTick()
243+
expect(effectCalls).toEqual([
244+
'before effect running',
245+
'effect cleanup',
246+
'effect',
247+
'effect ran',
248+
])
249+
expect(watchCalls).toEqual([
250+
'before watch running',
251+
'watch cleanup',
252+
'watch',
253+
'watch ran',
254+
])
255+
})
178256
})

packages/reactivity/src/baseWatch.ts

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ export interface BaseWatchOptions<Immediate = boolean> extends DebuggerOptions {
7171
deep?: boolean
7272
once?: boolean
7373
scheduler?: Scheduler
74+
middleware?: BaseWatchMiddleware
7475
onError?: HandleError
7576
onWarn?: HandleWarn
7677
}
@@ -83,6 +84,7 @@ export type Scheduler = (
8384
effect: ReactiveEffect,
8485
isInit: boolean,
8586
) => void
87+
export type BaseWatchMiddleware = (next: () => unknown) => any
8688
export type HandleError = (err: unknown, type: BaseWatchErrorCodes) => void
8789
export type HandleWarn = (msg: string, ...args: any[]) => void
8890

@@ -132,6 +134,7 @@ export function baseWatch(
132134
scheduler = DEFAULT_SCHEDULER,
133135
onWarn = __DEV__ ? warn : NOOP,
134136
onError = DEFAULT_HANDLE_ERROR,
137+
middleware,
135138
onTrack,
136139
onTrigger,
137140
}: BaseWatchOptions = EMPTY_OBJ,
@@ -211,6 +214,10 @@ export function baseWatch(
211214
activeEffect = currentEffect
212215
}
213216
}
217+
if (middleware) {
218+
const baseGetter = getter
219+
getter = () => middleware(baseGetter)
220+
}
214221
}
215222
} else {
216223
getter = NOOP
@@ -264,31 +271,38 @@ export function baseWatch(
264271
? (newValue as any[]).some((v, i) => hasChanged(v, oldValue[i]))
265272
: hasChanged(newValue, oldValue))
266273
) {
267-
// cleanup before running cb again
268-
if (cleanup) {
269-
cleanup()
274+
const next = () => {
275+
// cleanup before running cb again
276+
if (cleanup) {
277+
cleanup()
278+
}
279+
const currentEffect = activeEffect
280+
activeEffect = effect
281+
try {
282+
callWithAsyncErrorHandling(
283+
cb!,
284+
onError,
285+
BaseWatchErrorCodes.WATCH_CALLBACK,
286+
[
287+
newValue,
288+
// pass undefined as the old value when it's changed for the first time
289+
oldValue === INITIAL_WATCHER_VALUE
290+
? undefined
291+
: isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE
292+
? []
293+
: oldValue,
294+
onEffectCleanup,
295+
],
296+
)
297+
oldValue = newValue
298+
} finally {
299+
activeEffect = currentEffect
300+
}
270301
}
271-
const currentEffect = activeEffect
272-
activeEffect = effect
273-
try {
274-
callWithAsyncErrorHandling(
275-
cb,
276-
onError,
277-
BaseWatchErrorCodes.WATCH_CALLBACK,
278-
[
279-
newValue,
280-
// pass undefined as the old value when it's changed for the first time
281-
oldValue === INITIAL_WATCHER_VALUE
282-
? undefined
283-
: isMultiSource && oldValue[0] === INITIAL_WATCHER_VALUE
284-
? []
285-
: oldValue,
286-
onEffectCleanup,
287-
],
288-
)
289-
oldValue = newValue
290-
} finally {
291-
activeEffect = currentEffect
302+
if (middleware) {
303+
middleware(next)
304+
} else {
305+
next()
292306
}
293307
}
294308
} else {

packages/reactivity/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,5 +76,6 @@ export {
7676
traverse,
7777
BaseWatchErrorCodes,
7878
type BaseWatchOptions,
79+
type BaseWatchMiddleware,
7980
type Scheduler,
8081
} from './baseWatch'

0 commit comments

Comments
 (0)