diff --git a/packages/reactivity/__tests__/baseWatch.spec.ts b/packages/reactivity/__tests__/baseWatch.spec.ts index 329ebaacbf2..02d9e64e0fa 100644 --- a/packages/reactivity/__tests__/baseWatch.spec.ts +++ b/packages/reactivity/__tests__/baseWatch.spec.ts @@ -6,7 +6,7 @@ import { baseWatch, onEffectCleanup, ref, -} from '../src/index' +} from '../src' const queue: SchedulerJob[] = [] @@ -15,7 +15,7 @@ let isFlushPending = false const resolvedPromise = /*#__PURE__*/ Promise.resolve() as Promise const nextTick = (fn?: () => any) => fn ? resolvedPromise.then(fn) : resolvedPromise -const scheduler: Scheduler = ({ job }) => { +const scheduler: Scheduler = job => { queue.push(job) flushJobs() } diff --git a/packages/reactivity/src/baseWatch.ts b/packages/reactivity/src/baseWatch.ts index 8afd7424739..a97f43366b9 100644 --- a/packages/reactivity/src/baseWatch.ts +++ b/packages/reactivity/src/baseWatch.ts @@ -24,12 +24,13 @@ import { isReactive, isShallow } from './reactive' import { type Ref, isRef } from './ref' import { getCurrentScope } from './effectScope' -// contexts where user provided function may be executed, in addition to -// lifecycle hooks. +// These errors were transferred from `packages/runtime-core/src/errorHandling.ts` +// along with baseWatch to maintain code compatibility. Hence, +// it is essential to keep these values unchanged. export enum BaseWatchErrorCodes { - WATCH_GETTER = 'BaseWatchErrorCodes_WATCH_GETTER', - WATCH_CALLBACK = 'BaseWatchErrorCodes_WATCH_CALLBACK', - WATCH_CLEANUP = 'BaseWatchErrorCodes_WATCH_CLEANUP', + WATCH_GETTER = 2, + WATCH_CALLBACK, + WATCH_CLEANUP, } // TODO move to a scheduler package @@ -57,15 +58,12 @@ export interface SchedulerJob extends Function { } type WatchEffect = (onCleanup: OnCleanup) => void - type WatchSource = Ref | ComputedRef | (() => T) - type WatchCallback = ( value: V, oldValue: OV, onCleanup: OnCleanup, ) => any - type OnCleanup = (cleanupFn: () => void) => void export interface BaseWatchOptions extends DebuggerOptions { @@ -80,22 +78,19 @@ export interface BaseWatchOptions extends DebuggerOptions { // initial value for watchers to trigger on undefined initial values const INITIAL_WATCHER_VALUE = {} -export type Scheduler = (context: { - effect: ReactiveEffect - job: SchedulerJob - isInit: boolean -}) => void - -const DEFAULT_SCHEDULER: Scheduler = ({ job }) => job() - +export type Scheduler = ( + job: SchedulerJob, + effect: ReactiveEffect, + isInit: boolean, +) => void export type HandleError = (err: unknown, type: BaseWatchErrorCodes) => void +export type HandleWarn = (msg: string, ...args: any[]) => void +const DEFAULT_SCHEDULER: Scheduler = job => job() const DEFAULT_HANDLE_ERROR: HandleError = (err: unknown) => { throw err } -export type HandleWarn = (msg: string, ...args: any[]) => void - const cleanupMap: WeakMap void)[]> = new WeakMap() let activeEffect: ReactiveEffect | undefined = undefined @@ -306,12 +301,7 @@ export function baseWatch( // it is allowed to self-trigger (#1727) job.allowRecurse = !!cb - let effectScheduler: EffectScheduler = () => - scheduler({ - effect, - job, - isInit: false, - }) + let effectScheduler: EffectScheduler = () => scheduler(job, effect, false) effect = new ReactiveEffect(getter, NOOP, effectScheduler) @@ -342,11 +332,7 @@ export function baseWatch( oldValue = effect.run() } } else { - scheduler({ - effect, - job, - isInit: true, - }) + scheduler(job, effect, true) } return effect diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts index 6e2e51875dd..a8db2454a80 100644 --- a/packages/reactivity/src/index.ts +++ b/packages/reactivity/src/index.ts @@ -72,8 +72,8 @@ export { TrackOpTypes, TriggerOpTypes, ReactiveFlags } from './constants' export { baseWatch, onEffectCleanup, - BaseWatchErrorCodes, traverse, + BaseWatchErrorCodes, type BaseWatchOptions, type Scheduler, } from './baseWatch' diff --git a/packages/runtime-core/src/apiWatch.ts b/packages/runtime-core/src/apiWatch.ts index 0371dc57cac..b6c0d5f838d 100644 --- a/packages/runtime-core/src/apiWatch.ts +++ b/packages/runtime-core/src/apiWatch.ts @@ -8,9 +8,9 @@ import { getCurrentScope, } from '@vue/reactivity' import { - type SchedulerJob, - usePreScheduler, - useSyncScheduler, + type SchedulerFactory, + createPreScheduler, + createSyncScheduler, } from './scheduler' import { EMPTY_OBJ, @@ -28,7 +28,7 @@ import { unsetCurrentInstance, } from './component' import { handleError as handleErrorWithInstance } from './errorHandling' -import { usePostRenderScheduler } from './renderer' +import { createPostRenderScheduler } from './renderer' import { warn } from './warning' import type { ObjectWatchOptionItem } from './componentOptions' import { useSSRContext } from './helpers/useSsrContext' @@ -156,17 +156,15 @@ export function watch = false>( return doWatch(source as any, cb, options) } -function getSchedulerByFlushMode( - flush: WatchOptionsBase['flush'], -): SchedulerJob { +function getScheduler(flush: WatchOptionsBase['flush']): SchedulerFactory { if (flush === 'post') { - return usePostRenderScheduler + return createPostRenderScheduler } if (flush === 'sync') { - return useSyncScheduler + return createSyncScheduler } // default: 'pre' - return usePreScheduler + return createPreScheduler } function doWatch( @@ -224,12 +222,9 @@ function doWatch( } const instance = currentInstance - extendOptions.onError = (err: unknown, type: BaseWatchErrorCodes) => handleErrorWithInstance(err, instance, type) - - const scheduler = getSchedulerByFlushMode(flush)({ instance }) - extendOptions.scheduler = scheduler + extendOptions.scheduler = getScheduler(flush)(instance) let effect = baseWatch(source, cb, extend({}, options, extendOptions)) diff --git a/packages/runtime-core/src/componentOptions.ts b/packages/runtime-core/src/componentOptions.ts index ef1f14063ed..046520d9ed9 100644 --- a/packages/runtime-core/src/componentOptions.ts +++ b/packages/runtime-core/src/componentOptions.ts @@ -942,7 +942,7 @@ export function createWatcher( ? createPathGetter(publicThis, key) : () => (publicThis as any)[key] - const options: WatchOptions = {} + const options: WatchOptions = {} if (__COMPAT__) { const instance = getCurrentScope() === currentInstance?.scope ? currentInstance : null diff --git a/packages/runtime-core/src/errorHandling.ts b/packages/runtime-core/src/errorHandling.ts index 82de575c1e0..8686aee3880 100644 --- a/packages/runtime-core/src/errorHandling.ts +++ b/packages/runtime-core/src/errorHandling.ts @@ -10,7 +10,13 @@ import { BaseWatchErrorCodes } from '@vue/reactivity' export enum ErrorCodes { SETUP_FUNCTION, RENDER_FUNCTION, - NATIVE_EVENT_HANDLER, + // The error codes for the watch have been transferred to the reactivity + // package along with baseWatch to maintain code compatibility. Hence, + // it is essential to keep these values unchanged. + // WATCH_GETTER, + // WATCH_CALLBACK, + // WATCH_CLEANUP, + NATIVE_EVENT_HANDLER = 5, COMPONENT_EVENT_HANDLER, VNODE_HOOK, DIRECTIVE_HOOK, diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 88c8f370e84..4f5e8a99dae 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -38,7 +38,7 @@ import { isReservedProp, } from '@vue/shared' import { - type Scheduler, + type SchedulerFactory, type SchedulerJob, flushPostFlushCbs, flushPreFlushCbs, @@ -282,9 +282,8 @@ export const queuePostRenderEffect = __FEATURE_SUSPENSE__ : queueEffectWithSuspense : queuePostFlushCb -export const usePostRenderScheduler: Scheduler = - ({ instance }) => - ({ isInit, effect, job }) => { +export const createPostRenderScheduler: SchedulerFactory = + instance => (job, effect, isInit) => { if (isInit) { queuePostRenderEffect( effect.run.bind(effect), diff --git a/packages/runtime-core/src/scheduler.ts b/packages/runtime-core/src/scheduler.ts index 5b15a8ae6a3..2ab47e51dc1 100644 --- a/packages/runtime-core/src/scheduler.ts +++ b/packages/runtime-core/src/scheduler.ts @@ -1,7 +1,7 @@ import { ErrorCodes, callWithErrorHandling, handleError } from './errorHandling' import { type Awaited, NOOP, isArray } from '@vue/shared' import { type ComponentInternalInstance, getComponentName } from './component' -import type { ReactiveEffect } from '@vue/reactivity' +import type { Scheduler } from '@vue/reactivity' export interface SchedulerJob extends Function { id?: number @@ -289,17 +289,12 @@ function checkRecursiveUpdates(seen: CountMap, fn: SchedulerJob) { } } -export type Scheduler = (options: { - instance: ComponentInternalInstance | null -}) => (context: { - effect: ReactiveEffect - job: SchedulerJob - isInit: boolean -}) => void - -export const useSyncScheduler: Scheduler = - ({ instance }) => - ({ isInit, effect, job }) => { +export type SchedulerFactory = ( + instance: ComponentInternalInstance | null, +) => Scheduler + +export const createSyncScheduler: SchedulerFactory = + instance => (job, effect, isInit) => { if (isInit) { effect.run() } else { @@ -307,9 +302,8 @@ export const useSyncScheduler: Scheduler = } } -export const usePreScheduler: Scheduler = - ({ instance }) => - ({ isInit, effect, job }) => { +export const createPreScheduler: SchedulerFactory = + instance => (job, effect, isInit) => { if (isInit) { effect.run() } else {