代码层面,分了三个模块,一、UI渲染层,二、配置层,三、依赖处理层;
不复杂不复杂,清理完成后,比我想象的还要简单
1、UI渲染层:
2、配置层:
3、依赖处理逻辑层:
1、收集 表单项的所有依赖关系dependencies;
2、由Form组件的onValuesChange,来触发依赖项的动态更新,并在onValuesChange中收集子级依赖更新项,再手动(setState)触发下一轮的onValuesChange;
import { createFormItemType } from '@/pages/tool/launch/Market/components/CreateForm';
import { FormInstance } from 'antd/es/form';
import { useEffect, useMemo, useState } from 'react';
export type HandlersType = {
// 显示隐藏: 改变item的show属性值,
show?: (value: any, formData?: any, item?: createFormItemType) => boolean;
// 输入值:使用form.setFieldValue(key, newValue), 改变form[key]的值,
// 返回一个新的form[key]的值
valueChange?: (value: any, formData: any, item: createFormItemType) => any;
// 配置参数: 改变item的任意属性值, 该函数要返回一个新的item的属性的对象吗?还是直接覆盖item的属性值即可?
// 是show的升级版,可以代替show方法
propsChange?: (value: any, formData: any, item: createFormItemType) => any;
// TODO: 还有啥?
// TODO: 如果是异步方法怎么处理?
[key: string]:
| undefined
| ((value: any, formData: any, item: createFormItemType) => any);
};
export type DependenciesDefineType = {
reliedKey: string;
handlers: HandlersType;
};
export type DependenciesMapType = {
[reliedKey: string]: {
[key: string]: HandlersType;
};
};
interface Props {
form: FormInstance<any>;
createFormItems: { [key: string]: createFormItemType };
initialValue?: any;
}
export const useFormItemsRelys = (props: Props) => {
const { form, createFormItems, initialValue } = props;
// 运行时依赖项reliedKey收集
const [runningReliedKey, setRunningReliedKey] = useState<string[]>([]);
// 触发主组件重新render
const [, setRerender] = useState(0);
// 收集依赖
const { dependencies, formItems } = useMemo(() => {
const dependencies: DependenciesMapType = {};
// 初始化时 被依赖项
const initialDependentKeysMap = new Set();
const formItems = Object.entries(createFormItems).map(([key, config]) => {
if (config.dependencies && Array.isArray(config.dependencies)) {
config.dependencies.forEach(({ reliedKey, handlers }) => {
if (!dependencies[reliedKey]) {
dependencies[reliedKey] = {};
}
dependencies[reliedKey][key] = handlers as HandlersType;
// 收集 初始化时 被依赖项
initialDependentKeysMap.add(reliedKey);
});
}
config.key = key;
return config;
});
// 保存 初始化时 被依赖项
setRunningReliedKey([...initialDependentKeysMap] as React.SetStateAction<
string[]
>);
return {
formItems,
dependencies,
};
}, []);
// 命中依赖,一次只能命中一层
const onValuesChange = (changeValue: any, formData: any) => {
const newRunningReliedKey: React.SetStateAction<string[]> = [];
Object.entries(dependencies).forEach(([reliedKey, handlers]) => {
if (reliedKey in changeValue) {
Object.entries(handlers).forEach(([key, handler]) => {
/**
* 目前这个命中的方法是写在代码里面的,没有抽出单独的命中逻辑这个命中逻辑
* TODO:应该要抽一个单独的命中逻辑,并对handles做拓展
* TODO:并且不兼容Form.Item的name属性的数组格式
*/
// 每一个都是详细更新到当前的key对应的依赖项的, 不会更新到其他项的
const { show, valueChange, propsChange } = handler;
if (show || propsChange){
let updateItemProps: createFormItemType = {};
if (show) {
const isShow = show(
changeValue[reliedKey],
formData,
createFormItems[key],
);
updateItemProps['show'] = isShow;
}
if (propsChange) {
updateItemProps = propsChange(
changeValue[reliedKey],
formData,
createFormItems[key],
);
}
Object.assign(createFormItems[key], updateItemProps);
}
if (valueChange) {
const newFormValues = valueChange(
changeValue[reliedKey],
formData,
createFormItems[key],
);
// 不会触发主组件更新
form.setFieldValue(key, newFormValues);
}
if (key in dependencies) {
// 收集本次编辑,触发的子级被依赖字段
newRunningReliedKey.push(key);
}
});
return;
}
});
// 保存 子级被依赖字段,同时触发本次依赖命中的更新 触发渲染
if (newRunningReliedKey && !!newRunningReliedKey.length) {
setRunningReliedKey(newRunningReliedKey);
} else {
// 最后一层依赖的更新 触发渲染
setRerender(Date.now());
}
};
// 触发子级更新,不做初始化的无效更新
useEffect(() => {
if (runningReliedKey && !!runningReliedKey.length) {
const newFormData = form.getFieldsValue();
const curChangeValue: any = {};
runningReliedKey.forEach((reliedKey) => {
curChangeValue[reliedKey] = newFormData[reliedKey];
});
onValuesChange(curChangeValue, newFormData);
}
}, [runningReliedKey]);
return {
formItems,
onValuesChange,
};
};
AI优化版:
Qwen:
import { createFormItemType } from '@/pages/tool/launch/Market/components/CreateForm';
import { FormInstance } from 'antd/es/form';
import { useEffect, useMemo, useState, useCallback, useRef } from 'react';
export type HandlersType = {
show?: (value: any, formData?: any, item?: createFormItemType) => boolean;
valueChange?: (value: any, formData: any, item: createFormItemType) => any;
propsChange?: (value: any, formData: any, item: createFormItemType) => Partial<createFormItemType>;
[key: string]:
| undefined
| ((value: any, formData: any, item: createFormItemType) => any);
};
export type DependenciesDefineType = {
reliedKey: string;
handlers: HandlersType;
};
export type DependenciesMapType = {
[reliedKey: string]: {
[key: string]: HandlersType;
};
};
interface Props {
form: FormInstance<any>;
createFormItems: { [key: string]: createFormItemType };
initialValue?: any;
}
export const useFormItemsRelys = (props: Props) => {
const { form, createFormItems, initialValue } = props;
// 使用ref保存最新配置,避免闭包问题
const formItemsRef = useRef<{ [key: string]: createFormItemType }>(createFormItems);
formItemsRef.current = createFormItems;
// 收集依赖
const { dependencies, formItems } = useMemo(() => {
const dependencies: DependenciesMapType = {};
const initialDependentKeysMap = new Set<string>();
const processedFormItems = Object.entries(createFormItems).map(([key, config]) => {
const newConfig = { ...config, key };
if (Array.isArray(newConfig.dependencies)) {
newConfig.dependencies.forEach(({ reliedKey, handlers }) => {
if (!dependencies[reliedKey]) {
dependencies[reliedKey] = {};
}
dependencies[reliedKey][key] = handlers;
initialDependentKeysMap.add(reliedKey);
});
}
return newConfig;
});
return {
formItems: processedFormItems,
dependencies
};
}, [createFormItems]);
// 处理表单值变化
const onValuesChange = useCallback((changedValues: any, allValues: any) => {
const runningKeys = new Set<string>();
// 遍历所有被依赖的字段
Object.entries(dependencies).forEach(([reliedKey, handlers]) => {
// 检查当前变化的字段是否匹配依赖项
if (changedValues[reliedKey] !== undefined) {
Object.entries(handlers).forEach(([targetKey, handler]) => {
const targetItem = formItemsRef.current[targetKey];
const currentFormData = form.getFieldsValue();
if (targetItem) {
const { show, valueChange, propsChange } = handler;
const newValue = changedValues[reliedKey];
// 处理显示逻辑
if (show || propsChange) {
let updateProps: Partial<createFormItemType> = {};
if (show) {
updateProps.show = show(newValue, currentFormData, targetItem);
}
if (propsChange) {
updateProps = propsChange(newValue, currentFormData, targetItem);
}
// 更新表单项配置(需触发组件更新)
formItemsRef.current[targetKey] = {
...formItemsRef.current[targetKey],
...updateProps
};
}
// 处理值变化逻辑
if (valueChange) {
const newTargetValue = valueChange(newValue, currentFormData, targetItem);
form.setFieldValue(targetKey, newTargetValue);
}
// 收集触发的下一级依赖
if (targetKey in dependencies) {
runningKeys.add(targetKey);
}
}
});
}
});
// 触发下一级依赖更新
if (runningKeys.size > 0) {
const nextChange = {};
runningKeys.forEach(key => {
nextChange[key] = form.getFieldValue(key);
});
form.setFieldsValue(nextChange);
}
}, [dependencies]);
// 初始化时处理依赖
useEffect(() => {
if (initialValue) {
form.setFieldsValue(initialValue);
}
// 监听表单变化
const subscription = form.subscribe((changedValues, allValues) => {
onValuesChange(changedValues, allValues);
});
return () => {
subscription.unsubscribe();
};
}, [form, onValuesChange, initialValue]);
return {
formItems,
onValuesChange
};
};