perf(bi): optimize performance of chart filter block (#3316)

* perf: add useMemo

* fix: bug

* fix: bug

* chore: remove memo
This commit is contained in:
YANG QIA 2024-01-04 19:21:54 +08:00 committed by GitHub
parent 5f55f4d8db
commit f803105e69
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 89 additions and 77 deletions

View File

@ -54,12 +54,12 @@ export const Cascader = connect(
<Space split={'/'}> <Space split={'/'}>
{labels.map((label, index) => { {labels.map((label, index) => {
if (selectedOptions[index]) { if (selectedOptions[index]) {
return <span key={label}>{label}</span>; return <span key={index}>{label}</span>;
} }
const item = toArr(value) const item = toArr(value)
.filter(Boolean) .filter(Boolean)
.find((item) => item[fieldNames.value] === label); .find((item) => item[fieldNames.value] === label);
return <span key={label}>{item?.[fieldNames.label] || label}</span>; return <span key={index}>{item?.[fieldNames.label] || label}</span>;
})} })}
</Space> </Space>
); );

View File

@ -15,8 +15,7 @@ export class Table extends AntdChart {
key: item, key: item,
})) }))
: []; : [];
const rowKey = columns[0]?.dataIndex; const dataSource = data.map((item: any, index: number) => {
const dataSource = data.map((item: any) => {
Object.keys(item).map((key: string) => { Object.keys(item).map((key: string) => {
const props = fieldProps[key]; const props = fieldProps[key];
if (props?.interface === 'percent') { if (props?.interface === 'percent') {
@ -30,6 +29,7 @@ export class Table extends AntdChart {
item[key] = props.transformer(item[key]); item[key] = props.transformer(item[key]);
} }
}); });
item._key = index;
return item; return item;
}); });
const pageSize = advanced?.pagination?.pageSize || 10; const pageSize = advanced?.pagination?.pageSize || 10;
@ -47,7 +47,7 @@ export class Table extends AntdChart {
scroll: { scroll: {
x: 'max-content', x: 'max-content',
}, },
rowKey, rowKey: '_key',
...general, ...general,
...advanced, ...advanced,
}; };

View File

@ -205,8 +205,10 @@ export const ChartConfigure: React.FC<{
}); });
}} }}
width={'95%'} width={'95%'}
bodyStyle={{ styles={{
background: 'rgba(128, 128, 128, 0.08)', body: {
background: 'rgba(128, 128, 128, 0.08)',
},
}} }}
> >
<FormProvider form={form}> <FormProvider form={form}>
@ -411,7 +413,8 @@ ChartConfigure.Data = function Data() {
const error = service?.error; const error = service?.error;
return !error ? ( return !error ? (
<Table <Table
dataSource={data} dataSource={data.map((item, index) => ({ ...item, _key: index }))}
rowKey="_key"
scroll={{ x: 'max-content' }} scroll={{ x: 'max-content' }}
columns={Object.keys(data[0] || {}).map((col) => { columns={Object.keys(data[0] || {}).map((col) => {
const field = getField(fields, col.split('.')); const field = getField(fields, col.split('.'));

View File

@ -312,9 +312,9 @@ export const querySchema: ISchema = {
overflow: 'auto', overflow: 'auto',
}, },
}, },
enum: '{{ filterOptions }}',
'x-component': 'Filter', 'x-component': 'Filter',
'x-component-props': { 'x-component-props': {
options: '{{ filterOptions }}',
dynamicComponent: 'FilterDynamicComponent', dynamicComponent: 'FilterDynamicComponent',
}, },
}, },

View File

@ -13,7 +13,7 @@ import {
useGlobalTheme, useGlobalTheme,
useSchemaInitializerItem, useSchemaInitializerItem,
} from '@nocobase/client'; } from '@nocobase/client';
import React, { useCallback, useContext, useMemo } from 'react'; import React, { memo, useCallback, useContext, useMemo } from 'react';
import { lang, useChartsTranslation } from '../locale'; import { lang, useChartsTranslation } from '../locale';
import { Schema, SchemaOptionsContext, observer, useField, useFieldSchema, useForm } from '@formily/react'; import { Schema, SchemaOptionsContext, observer, useField, useFieldSchema, useForm } from '@formily/react';
import { useMemoizedFn } from 'ahooks'; import { useMemoizedFn } from 'ahooks';
@ -92,7 +92,7 @@ export const ChartFilterFormItem = observer(
export const ChartFilterCustomItemInitializer: React.FC<{ export const ChartFilterCustomItemInitializer: React.FC<{
insert?: any; insert?: any;
}> = (props) => { }> = memo((props) => {
const { locale } = useContext(ConfigProvider.ConfigContext); const { locale } = useContext(ConfigProvider.ConfigContext);
const { t: lang } = useChartsTranslation(); const { t: lang } = useChartsTranslation();
const t = useMemoizedFn(lang); const t = useMemoizedFn(lang);
@ -214,7 +214,7 @@ export const ChartFilterCustomItemInitializer: React.FC<{
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [theme]); }, [theme]);
return <SchemaInitializerItem {...itemConfig} {...props} onClick={handleClick} />; return <SchemaInitializerItem {...itemConfig} {...props} onClick={handleClick} />;
}; });
export const chartFilterItemInitializers = new SchemaInitializer({ export const chartFilterItemInitializers = new SchemaInitializer({
name: 'ChartFilterItemInitializers', name: 'ChartFilterItemInitializers',
@ -232,16 +232,19 @@ export const chartFilterItemInitializers = new SchemaInitializer({
const { getChartCollections } = useChartData(); const { getChartCollections } = useChartData();
const { getChartFilterFields } = useChartFilter(); const { getChartFilterFields } = useChartFilter();
const collections = getChartCollections(); const collections = getChartCollections();
return collections.map((name: any) => {
const collection = getCollection(name); return useMemo(() => {
const fields = getChartFilterFields(collection); return collections.map((name: any) => {
return { const collection = getCollection(name);
name: collection.key, const fields = getChartFilterFields(collection);
type: 'subMenu', return {
title: collection.title, name: collection.key,
children: fields, type: 'subMenu',
}; title: collection.title,
}); children: fields,
};
});
}, [collections]);
}, },
}, },
{ {

View File

@ -412,26 +412,28 @@ export const useChartFilterSourceFields = () => {
}; };
const collections = getChartCollections(); const collections = getChartCollections();
const options = []; return useMemo(() => {
collections.forEach((name) => { const options = [];
const collection = getCollection(name); collections.forEach((name) => {
const children = []; const collection = getCollection(name);
const fields = getCollectionFields(collection); const children = [];
fields.forEach((field) => { const fields = getCollectionFields(collection);
const option = field2option(field, 1); fields.forEach((field) => {
if (option) { const option = field2option(field, 1);
children.push(option); if (option) {
children.push(option);
}
});
if (children.length) {
options.push({
value: name,
label: t(collection.title),
children,
});
} }
}); });
if (children.length) { return options;
options.push({ }, [collections]);
value: name,
label: t(collection.title),
children,
});
}
});
return options;
}; };
export const useFieldComponents = () => { export const useFieldComponents = () => {

View File

@ -1,7 +1,7 @@
import { ArrayField } from '@formily/core'; import { ArrayField } from '@formily/core';
import { ISchema, Schema, useForm } from '@formily/react'; import { ISchema, Schema, useForm } from '@formily/react';
import { CollectionFieldOptions, useACLRoleContext, useCollectionManager } from '@nocobase/client'; import { CollectionFieldOptions, useACLRoleContext, useCollectionManager } from '@nocobase/client';
import { useContext } from 'react'; import { useContext, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { ChartConfigContext } from '../configure'; import { ChartConfigContext } from '../configure';
import formatters from '../block/formatters'; import formatters from '../block/formatters';
@ -51,43 +51,47 @@ export const useFieldsWithAssociation = (collection?: string) => {
const { getCollectionFields, getInterface } = useCollectionManager(); const { getCollectionFields, getInterface } = useCollectionManager();
const { t } = useTranslation(); const { t } = useTranslation();
const fields = useFields(collection); const fields = useFields(collection);
return fields.map((field) => { return useMemo(
const filterable = getInterface(field.interface)?.filterable; () =>
const label = Schema.compile(field.uiSchema?.title || field.name, { t }); fields.map((field) => {
if (!(filterable && (filterable?.nested || filterable?.children?.length))) { const filterable = getInterface(field.interface)?.filterable;
return { ...field, label }; const label = Schema.compile(field.uiSchema?.title || field.name, { t });
} if (!(filterable && (filterable?.nested || filterable?.children?.length))) {
let targetFields = []; return { ...field, label };
if (filterable?.nested) { }
const nestedFields = (getCollectionFields(field.target) || []) let targetFields = [];
.filter((targetField) => { if (filterable?.nested) {
return targetField.interface; const nestedFields = (getCollectionFields(field.target) || [])
}) .filter((targetField) => {
.map((targetField) => ({ return targetField.interface;
...targetField, })
key: `${field.name}.${targetField.name}`, .map((targetField) => ({
label: `${label} / ${Schema.compile(targetField.uiSchema?.title || targetField.name, { t })}`, ...targetField,
value: `${field.name}.${targetField.name}`, key: `${field.name}.${targetField.name}`,
})); label: `${label} / ${Schema.compile(targetField.uiSchema?.title || targetField.name, { t })}`,
targetFields = [...targetFields, ...nestedFields]; value: `${field.name}.${targetField.name}`,
} }));
targetFields = [...targetFields, ...nestedFields];
}
if (filterable?.children?.length) { if (filterable?.children?.length) {
const children = filterable.children.map((child: any) => ({ const children = filterable.children.map((child: any) => ({
...child, ...child,
key: `${field.name}.${child.name}`, key: `${field.name}.${child.name}`,
label: `${label} / ${Schema.compile(child.schema?.title || child.title || child.name, { t })}`, label: `${label} / ${Schema.compile(child.schema?.title || child.title || child.name, { t })}`,
value: `${field.name}.${child.name}`, value: `${field.name}.${child.name}`,
})); }));
targetFields = [...targetFields, ...children]; targetFields = [...targetFields, ...children];
} }
return { return {
...field, ...field,
label, label,
targetFields, targetFields,
}; };
}); }),
[fields],
);
}; };
export const useChartFields = (fields: FieldOption[]) => (field: any) => { export const useChartFields = (fields: FieldOption[]) => (field: any) => {
@ -139,7 +143,7 @@ export const useCollectionOptions = () => {
value: collection.name, value: collection.name,
key: collection.name, key: collection.name,
})); }));
return Schema.compile(options, { t }); return useMemo(() => Schema.compile(options, { t }), [options]);
}; };
export const useOrderFieldsOptions = (defaultOptions: any[], fields: FieldOption[]) => (field: any) => { export const useOrderFieldsOptions = (defaultOptions: any[], fields: FieldOption[]) => (field: any) => {