◆
Vue3 keep-alive 下 watch 只在当前路由触发的方法
场景
项目中使用了 keepalive,但经常会在不同的路由页面去监听一些全局状态管理的数据,或者是监听了路由相关的数据, 但是由于使用了 keepalive,在当前路由页面访问后,又离开,watch 并不会卸载掉,也就是,如果监听的数据发生了变化, 在非当前的路由页面,watch 也会触发,大多数情况下,这种副作用是不需要的。
解决方法
思路很简单,因为用到了 keepalive,所以我们主要在 onActivated, onDeactivated 生命周期中,启动与停止 watch
代码实现如下,类型先用 any 替代
/**
* @description watch 监听,离开页面暂停,进入页面重新激活监听
* @param sources
* @param cb
* @param options
*/
export function useCurrentPageWatch(
source: any,
cb: any,
options: WatchOptions = {},
): void {
let stopWatching: WatchStopHandle | null;
// 创建一个开启 wacth 监听的函数
const startWatching = () => {
// 利用 watch 返回的 stop 函数,进行停止监听
stopWatching = watch(source, cb, options);
};
// 停止现有的 watch,以防之前的 watch 仍在运行
const stopWatchingIfNeeded = () => {
if (stopWatching) {
stopWatching();
stopWatching = null;
}
};
// 页面激活时启动 watch
onActivated(() => {
stopWatchingIfNeeded();
startWatching();
});
// 页面失活时停止 watch
onDeactivated(() => {
stopWatchingIfNeeded();
});
}
逻辑写完后,还要给函数添加上对应的 ts 类型,由于我们的函数还是依赖于 watch,所以我们的函数类型是和 watch 一致的,完整版代码如下
import type {
WatchCallback,
WatchOptions,
WatchSource,
WatchStopHandle,
wacth,
} from 'vue';
type MapSources<T, Immediate> = {
[K in keyof T]: T[K] extends WatchSource<infer V>
? Immediate extends true
? V | undefined
: V
: T[K] extends object
? Immediate extends true
? T[K] | undefined
: T[K]
: never;
};
type MultiWatchSources = (WatchSource<unknown> | object)[];
/**
* @description watch 监听,离开页面暂停,进入页面重新激活监听
* @param sources
* @param cb
* @param options
*/
export function useCurrentPageWatch<
T extends MultiWatchSources,
Immediate extends Readonly<boolean> = false,
>(
sources: [...T],
cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
options?: WatchOptions,
): void;
export function useCurrentPageWatch<
T extends Readonly<MultiWatchSources>,
Immediate extends Readonly<boolean> = false,
>(
source: T,
cb: WatchCallback<MapSources<T, false>, MapSources<T, Immediate>>,
options?: WatchOptions,
): void;
export function useCurrentPageWatch<
T,
Immediate extends Readonly<boolean> = false,
>(
source: WatchSource<T>,
cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
options?: WatchOptions,
): void;
export function useCurrentPageWatch<
T extends object,
Immediate extends Readonly<boolean> = false,
>(
source: T,
cb: WatchCallback<T, Immediate extends true ? T | undefined : T>,
options?: WatchOptions,
): void;
export function useCurrentPageWatch(
source: any,
cb: any,
options: WatchOptions = {},
): void {
let stopWatching: WatchStopHandle | null;
const startWatching = () => {
stopWatching = watch(source, cb, options);
};
const stopWatchingIfNeeded = () => {
if (stopWatching) {
stopWatching();
stopWatching = null;
}
};
// 页面激活时启动 watch
onActivated(() => {
stopWatchingIfNeeded(); // 停止现有的 watch,以防之前的 watch 仍在运行
startWatching();
});
// 页面失活时停止 watch
onDeactivated(() => {
stopWatchingIfNeeded();
});
}

还没有留言,来发表第一条吧~