useDeepWatch Composable
Enhanced deep watch with debounce, immediate execution and cleanup
Code
import { watch, type Ref, type WatchSource, onUnmounted } from 'vue';
export function useDeepWatch<T>(
source: WatchSource<T> | WatchSource<T>[],
callback: (newVal: T, oldVal: T) => void | Promise<void>,
options: {
deep?: boolean;
immediate?: boolean;
debounce?: number;
flush?: 'pre' | 'post' | 'sync';
} = { deep: true, immediate: false, debounce: 0 }
) {
let debounceTimeout: ReturnType<typeof setTimeout> | null = null;
let cleanupFn: (() => void) | null = null;
// Wrapped callback with debounce
const wrappedCallback = (newVal: T, oldVal: T) => {
__TOKEN_28__ (options.debounce && options.debounce > 0) {
__TOKEN_29__ (debounceTimeout) clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(() => {
callback(newVal, oldVal);
}, options.debounce);
} else {
callback(newVal, oldVal);
}
};
// Create watcher
const stopWatch = watch(
source as any,
wrappedCallback,
{
deep: options.deep ?? true,
immediate: options.immediate ?? false,
flush: options.flush ?? 'pre'
}
);
// Cleanup function
const cleanup = () => {
stopWatch();
__TOKEN_33__ (debounceTimeout) clearTimeout(debounceTimeout);
__TOKEN_34__ (cleanupFn) cleanupFn();
};
// Register cleanup on unmount
onUnmounted(cleanup);
// Allow setting custom cleanup
const setCleanup = (fn: () => void) => {
cleanupFn = fn;
};
return {
stop: stopWatch,
cleanup,
setCleanup
};
}
// Usage example
// const formData = ref({ name: '', address: { city: '', zip: '' } });
// const { cleanup } = useDeepWatch(
// formData,
// (newVal, oldVal) => console.log('Form changed:', newVal),
// { debounce: 300, immediate: true }
// );
// cleanup(); // Manual cleanup