import { cloneDeep } from 'lodash-es'
import { reactive, ref, watchEffect } from 'vue'
/**
* 神奇函数
* @param source 数据源,
* @param initKey 固定需要返回的属性
* @description 收集数据源中修改的属性,并返回
* @version 1.0 仅支持对象
* @author sufei
* @return { source, result }
*/
export function useMagical(source: any, initKey?: string[]) {
const result = reactive<any>({})
// 神奇函数启动状态
const starting = ref(false)
// 对数据源进行深度copy
let sourceCache: any = {}
watchEffect(() => {
if (!starting.value) return
Object.keys(sourceCache).forEach((key) => {
if (JSON.stringify(source[key]) !== JSON.stringify(sourceCache[key])) {
result[key] = source[key]
} else if (initKey?.includes(key)) {
result[key] = source[key]
}
})
})
/* 启动神奇函数*/
function startMagical(val?: Record<string, any>) {
if (val) {
setSourceCache(val)
} else {
sourceCache = cloneDeep(source)
}
if (initKey && initKey.length > 0) {
initKey.forEach((key) => {
result[key] = source[key] || null
})
}
starting.value = true
}
function setSourceCache(val: any) {
sourceCache = {}
Object.keys(val).forEach((key) => {
sourceCache[key] = undefined
})
}
return {
source,
result,
startMagical,
}
}
这个
useMagical
函数是一个自定义的 Vue Hooks,用于跟踪和反映数据源对象的变化。它通过watchEffect
监听source
的变化,并将变化的属性反映到result
中。
问题分析:
类型安全问题:source
参数的类型被声明为 any
,这可能导致类型检查失效。应该使用更具体的类型来确保类型安全。
**副作用控制问题:**在 watchEffec
t 中直接修改 result
,这可能导致不必要的副作用。应该使用更可控的方式来更新 result
。
性能问题:在每次 source
变化时,都会遍历 sourceCache
的所有键,这可能在数据源较大时影响性能。可以考虑使用更高效的算法来减少不必要的遍历。
修复建议:
**类型安全: **使用 TypeScript
的类型系统来确保 source
和 result
的类型安全。可以使用 Record<string, any>
或更具体的类型来定义 source
和 result
。
副作用控制: 使用 reactive
或 ref
来创建响应式对象,并使用 Vue
的 set
方法来更新 result
,以避免直接修改响应式对象。
性能优化: 使用 Map
来存储 sourceCache
,这样可以更高效地查找和更新键值对。同时,可以使用 watch
来监听特定的属性,而不是整个 source
对象。
import { cloneDeep, isEqual } from 'lodash-es';
import { reactive, ref, watchEffect } from 'vue';
/**
* 神奇函数
* @param source 数据源,
* @param initKey 固定需要返回的属性
* @description 收集数据源中修改的属性,并返回
* @version 1.0 仅支持对象
* @author sufei
* @return { source, result }
*/
export function useMagical<T extends Record<string, any>>(source: T, initKey?: string[]) {
const result = reactive<T>({} as T);
// 神奇函数启动状态
const starting = ref(false);
// 对数据源进行深度copy
const sourceCache = ref<T>({} as T);
watchEffect(() => {
if (!starting.value) return;
Object.keys(source).forEach((key) => {
if (!isEqual(source[key], sourceCache.value[key])) {
result[key] = source[key];
} else if (initKey?.includes(key)) {
result[key] = source[key];
}
});
});
/* 启动神奇函数*/
function startMagical(val?: T) {
if (val) {
setSourceCache(val);
} else {
sourceCache.value = cloneDeep(source);
}
if (initKey && initKey.length > 0) {
initKey.forEach((key) => {
result[key] = source[key] || null;
});
}
starting.value = true;
}
function setSourceCache(val: T) {
sourceCache.value = {} as T;
Object.keys(val).forEach((key) => {
sourceCache.value[key] = undefined;
});
}
return {
source,
result,
startMagical,
};
}
修复说明:
类型安全:
使用 T extends Record<string, any>
来确保 source
和 result
是对象类型。
使用 reactive<T>({} as T)
和 ref<T>({} as T)
来确保类型安全。
副作用控制:
使用 reactive
和 ref
来创建响应式对象。
使用watchEffect
来监听 source
的变化,并使用 isEqual
来比较值是否相等。
性能优化:
使用 ref
来存储 sourceCache
,并在 startMagical
函数中使用 cloneDeep
来深度复制 source
。