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 formVariabele = useFormVariable({ blockForm: form, rootCollection });
const iterationVariabele = useIterationVariable({ const iterationVariabele = useIterationVariable({
blockForm: form, blockForm: form,
collectionField, currentCollection: collectionField.collectionName,
rootCollection, rootCollection,
}); });

View File

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

View File

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

View File

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