refactor: performance optimization of association field data scope (#2113)

* refactor:  performance optimization of association field data scope

* refactor: disabled

* refactor: disabled

* refactor: code improve
This commit is contained in:
katherinehhh 2023-07-06 17:55:28 +08:00 committed by GitHub
parent ed9d716d7d
commit a9aab8ed92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 108 additions and 66 deletions

View File

@ -13,7 +13,7 @@ export const ChildDynamicComponent = observer(
const formVariabele = useFormVariable({ blockForm: form, rootCollection });
const iterationVariabele = useIterationVariable({
blockForm: form,
collectionField,
currentCollection: collectionField.collectionName,
rootCollection,
});

View File

@ -11,11 +11,12 @@ interface GetOptionsParams {
loadChildren?: (option: Option) => Promise<void>;
getFilterOptions?: (collectionName: string) => any[];
compile: (value: string) => any;
schema?: any;
}
const getChildren = (
options: FieldOption[],
{ depth, maxDepth, loadChildren, compile }: GetOptionsParams,
{ depth, maxDepth, loadChildren, compile, schema }: GetOptionsParams,
): Option[] => {
const result = options
.map((option): Option => {
@ -25,6 +26,8 @@ const getChildren = (
value: option.name,
label: compile(option.title),
depth,
// TODO: 现在是通过组件的名称来过滤能够被选择的选项,这样的坏处是不够精确,后续可以优化
disabled: schema?.['x-component'] !== option.schema?.['x-component'],
};
}
@ -50,11 +53,13 @@ export const useFormVariable = ({
rootCollection,
operator,
level,
schema,
}: {
blockForm?: any;
rootCollection: string;
operator?: any;
level?: number;
schema?: any;
}) => {
const compile = useCompile();
const { t } = useTranslation();
@ -82,6 +87,7 @@ export const useFormVariable = ({
maxDepth: 4,
loadChildren,
compile,
schema,
}) || [];
if (children.length === 0) {
option.disabled = true;

View File

@ -1,94 +1,125 @@
import { Schema } from '@formily/react';
import { useMemo } from 'react';
import { useCollectionManager } from '../../../collection-manager';
import { useCompile, useGetFilterOptions } from '../../../schema-component';
import { FieldOption, Option } from '../type';
interface GetOptionsParams {
schema: any;
depth: number;
operator?: string;
maxDepth: number;
count?: number;
getFilterOptions: (collectionName: string) => any[];
loadChildren?: (option: Option) => Promise<void>;
getFilterOptions?: (collectionName: string) => any[];
compile: (value: string) => any;
schema: any;
}
const getChildren = (options: any[], { schema, operator, maxDepth, count = 1, getFilterOptions }: GetOptionsParams) => {
if (count > maxDepth) {
return [];
}
const result = options.map((option) => {
if ((option.type !== 'belongsTo' && option.type !== 'hasOne') || !option.target) {
const getChildren = (
options: FieldOption[],
{ depth, maxDepth, loadChildren, compile, schema }: GetOptionsParams,
): Option[] => {
const result = options
.map((option): Option => {
if (!option.target) {
return {
key: option.name,
value: option.name,
label: option.title,
label: compile(option.title),
depth,
// TODO: 现在是通过组件的名称来过滤能够被选择的选项,这样的坏处是不够精确,后续可以优化
// disabled: schema?.['x-component'] !== option.schema?.['x-component'],
disabled: false,
disabled: schema?.['x-component'] !== option.schema?.['x-component'],
};
}
const children =
getChildren(getFilterOptions(option.target), {
schema,
operator,
maxDepth,
count: count + 1,
getFilterOptions,
}) || [];
if (depth >= maxDepth) {
return null;
}
return {
key: option.name,
value: option.name,
label: option.title,
children,
disabled: children.every((child) => child.disabled),
label: compile(option.title),
children: [],
isLeaf: false,
field: option,
depth,
loadChildren,
};
});
})
.filter(Boolean);
return result;
};
export const useIterationVariable = ({
blockForm,
collectionField,
currentCollection,
operator,
schema,
level,
rootCollection,
}: {
blockForm?: any;
collectionField: any;
currentCollection: string;
rootCollection: string;
operator?: any;
schema?: any;
level?: number;
rootCollection?: string;
}) => {
const compile = useCompile();
const getFilterOptions = useGetFilterOptions();
const fields = getFilterOptions(collectionField?.collectionName);
const children = useMemo(() => {
const allowFields = fields.filter((field) => {
return Object.keys(blockForm.fields).some((name) => name.includes(field.name));
const loadChildren = (option: any): Promise<void> => {
if (!option.field?.target) {
return new Promise((resolve) => {
resolve(void 0);
});
return (
getChildren(allowFields, {
schema,
operator,
maxDepth: level || 3,
getFilterOptions,
}) || []
);
}, [operator, schema, blockForm]);
}
return useMemo(() => {
return rootCollection !== collectionField?.collectionName && children.length > 0
? compile({
const collectionName = option.field.target;
const fields = getFilterOptions(collectionName);
const allowFields =
option.depth === 0
? fields.filter((field) => {
return Object.keys(blockForm.fields).some((name) => name.includes(`.${field.name}`));
})
: fields;
return new Promise((resolve) => {
setTimeout(() => {
const children =
getChildren(allowFields, {
depth: option.depth + 1,
maxDepth: 4,
loadChildren,
compile,
schema,
}) || [];
if (children.length === 0) {
option.disabled = true;
resolve();
return;
}
option.children = children;
resolve();
// 延迟 5 毫秒,防止阻塞主线程,导致 UI 卡顿
}, 5);
});
};
const result = useMemo(() => {
return (
blockForm &&
currentCollection !== rootCollection && {
label: `{{t("Current object")}}`,
value: '$iteration',
key: '$iteration',
disabled: children.every((option) => option.disabled),
children: children,
})
: null;
}, [children]);
children: [],
isLeaf: false,
field: {
target: currentCollection,
},
depth: 0,
loadChildren,
}
);
}, [currentCollection]);
return result;
};

View File

@ -9,8 +9,13 @@ export const useVariableOptions = ({ form, collectionField, rootCollection }: an
const { operator, schema } = useValues();
const userVariable = useUserVariable({ maxDepth: 3, schema });
const dateVariable = useDateVariable({ operator, schema });
const formVariabele = useFormVariable({ blockForm: form, rootCollection });
const iterationVariabele = useIterationVariable({ blockForm: form, collectionField, schema, rootCollection });
const formVariabele = useFormVariable({ blockForm: form, schema, rootCollection });
const iterationVariabele = useIterationVariable({
blockForm: form,
currentCollection: collectionField.collectionName,
schema,
rootCollection,
});
const result = useMemo(
() => [userVariable, dateVariable, formVariabele, iterationVariabele].filter(Boolean),