From 2c3a04c5c174b5166f867021a44710a97ff248ea Mon Sep 17 00:00:00 2001 From: dream2023 <1098626505@qq.com> Date: Wed, 6 Mar 2024 15:17:12 +0800 Subject: [PATCH] fix: schema component options add memo --- .../src/acl/Configuration/ScopeSelect.tsx | 15 ++++-- .../BlockSchemaComponentProvider.tsx | 50 ++++++++++--------- .../src/block-provider/TableBlockProvider.tsx | 3 +- .../block-provider/TableSelectorProvider.tsx | 7 +-- .../core/client/src/china-region/index.tsx | 5 +- .../Configuration/AddCollectionAction.tsx | 15 ++---- .../route-switch/antd/admin-layout/index.tsx | 9 +++- .../antd/association-field/SubTable.tsx | 42 +++++++++------- .../antd/grid-card/GridCard.tsx | 12 +++-- .../schema-component/core/SchemaComponent.tsx | 26 ++++++---- .../core/SchemaComponentProvider.tsx | 42 +++++++++------- .../SystemSettingsShortcut.tsx | 5 +- .../src/client/ImportPluginProvider.tsx | 29 +++++++---- 13 files changed, 152 insertions(+), 108 deletions(-) diff --git a/packages/core/client/src/acl/Configuration/ScopeSelect.tsx b/packages/core/client/src/acl/Configuration/ScopeSelect.tsx index 1d4c6e4847..01f95f95bb 100644 --- a/packages/core/client/src/acl/Configuration/ScopeSelect.tsx +++ b/packages/core/client/src/acl/Configuration/ScopeSelect.tsx @@ -29,15 +29,20 @@ export const ScopeSelect = (props) => { }), [], ); + + const scope = useMemo(() => { + return { + onChange(value) { + props?.onChange?.(value); + }, + }; + }, [props?.onChange]) + return ( diff --git a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx index fc08fc1e1e..dcab2dcce4 100644 --- a/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx +++ b/packages/core/client/src/block-provider/BlockSchemaComponentProvider.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useMemo } from 'react'; import { Plugin } from '../application/Plugin'; import { ActionSchemaToolbar } from '../modules/actions/ActionSchemaToolbar'; import { CollapseItemSchemaToolbar } from '../modules/blocks/filter-blocks/collapse/CollapseItemSchemaToolbar'; @@ -18,30 +18,34 @@ import { BlockSchemaToolbar } from '../modules/blocks/BlockSchemaToolbar'; // TODO: delete this, replaced by `BlockSchemaComponentPlugin` export const BlockSchemaComponentProvider: React.FC = (props) => { + const components = useMemo(() => ({ + TableFieldProvider, + TableBlockProvider, + TableSelectorProvider, + FormBlockProvider, + FilterFormBlockProvider, + FormFieldProvider, + DetailsBlockProvider, + RecordLink, + }), []) + + const scope = useMemo(() => ({ + ...bp, + useSourceIdFromRecord, + useSourceIdFromParentRecord, + useParamsFromRecord, + useFormBlockProps, + useFormFieldProps, + useDetailsBlockProps, + useTableFieldProps, + useTableBlockProps, + useTableSelectorProps, + }), []) + return ( {props.children} diff --git a/packages/core/client/src/block-provider/TableBlockProvider.tsx b/packages/core/client/src/block-provider/TableBlockProvider.tsx index 517ef47a21..2c6300da1d 100644 --- a/packages/core/client/src/block-provider/TableBlockProvider.tsx +++ b/packages/core/client/src/block-provider/TableBlockProvider.tsx @@ -111,8 +111,9 @@ export const TableBlockProvider = (props) => { }; }, [parsedFilter, params]); + const scope = useMemo(() => ({ treeTable }), [treeTable]); return ( - + diff --git a/packages/core/client/src/block-provider/TableSelectorProvider.tsx b/packages/core/client/src/block-provider/TableSelectorProvider.tsx index 4d422b8e8d..fbcdd834a3 100644 --- a/packages/core/client/src/block-provider/TableSelectorProvider.tsx +++ b/packages/core/client/src/block-provider/TableSelectorProvider.tsx @@ -2,7 +2,7 @@ import { ArrayField } from '@formily/core'; import { Schema, useField, useFieldSchema } from '@formily/react'; import _ from 'lodash'; import uniq from 'lodash/uniq'; -import React, { createContext, useContext, useEffect, useState } from 'react'; +import React, { createContext, useContext, useEffect, useMemo, useState } from 'react'; import { useCollectionManager_deprecated } from '../collection-manager'; import { useCollectionParentRecordData } from '../data-source/collection-record/CollectionRecordProvider'; import { isInFilterFormBlock } from '../filter-provider'; @@ -153,6 +153,8 @@ export const TableSelectorProvider = (props: TableSelectorProviderProps) => { const collection = getCollection(collectionField?.collectionName); const primaryKey = collection?.getPrimaryKey(); const appends = useAssociationNames(props.collection); + const scope = useMemo(() => ({ treeTable }), [treeTable]); + let params = { ...props.params }; if (props.dragSort) { params['sort'] = ['sort']; @@ -255,9 +257,8 @@ export const TableSelectorProvider = (props: TableSelectorProviderProps) => { if (params?.filter) { params.filter = parsedFilter; } - return ( - + diff --git a/packages/core/client/src/china-region/index.tsx b/packages/core/client/src/china-region/index.tsx index dcbe51d92e..1b3b1a018e 100644 --- a/packages/core/client/src/china-region/index.tsx +++ b/packages/core/client/src/china-region/index.tsx @@ -1,7 +1,7 @@ import { ArrayField } from '@formily/core'; import { useField } from '@formily/react'; import { error } from '@nocobase/utils/client'; -import React from 'react'; +import React, { useMemo } from 'react'; import { SchemaComponentOptions } from '..'; import { useAPIClient, useRequest } from '../api-client'; @@ -74,8 +74,9 @@ const useChinaRegionLoadData = () => { }; export const ChinaRegionProvider = (props) => { + const scope = useMemo(() => ({ useChinaRegionDataSource, useChinaRegionLoadData }), []); return ( - + {props.children} ); diff --git a/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx b/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx index 82ea4e9939..83dd505b89 100644 --- a/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/AddCollectionAction.tsx @@ -180,6 +180,9 @@ export const AddCollectionAction = (props) => { }; }, [category, items]); + const components = useMemo(() => ({ ...components, ArrayTable, TemplateSummary }), []); + const scopes = useMemo(() => ({ getContainer, useCancelAction, useCreateCollection, record, ...scope }), [scope]); + return ( @@ -192,16 +195,8 @@ export const AddCollectionAction = (props) => { diff --git a/packages/core/client/src/route-switch/antd/admin-layout/index.tsx b/packages/core/client/src/route-switch/antd/admin-layout/index.tsx index f237c81f62..a17a949ff3 100644 --- a/packages/core/client/src/route-switch/antd/admin-layout/index.tsx +++ b/packages/core/client/src/route-switch/antd/admin-layout/index.tsx @@ -199,12 +199,19 @@ const MenuEditor = (props) => { }, ); + const scope = useMemo(() => ({ + useMenuProps, + onSelect, + sideMenuRef, + defaultSelectedUid + }), []) + if (loading) { return render(); } return ( - + ); }; diff --git a/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx b/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx index 4e31ebc648..91ad692977 100644 --- a/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx +++ b/packages/core/client/src/schema-component/antd/association-field/SubTable.tsx @@ -29,6 +29,22 @@ import { useTableSelectorProps } from './InternalPicker'; import { getLabelFormatValue, useLabelUiSchema } from './util'; import { markRecordAsNew } from '../../../data-source/collection-record/isNewRecord'; + +const usePickActionProps = () => { + const { setVisible } = useActionContext(); + const { selectedRows, options, collectionField } = useContext(RecordPickerContext); + const { field } = useAssociationFieldContext(); + return { + onClick() { + const selectData = unionBy(selectedRows, options, collectionField?.targetKey || 'id'); + const data = field.value || []; + field.value = uniqBy(data.concat(selectData), collectionField?.targetKey || 'id'); + field.onInput(field.value); + setVisible(false); + }, + }; +}; + export const SubTable: any = observer( (props: any) => { const { openSize } = props; @@ -88,25 +104,19 @@ export const SubTable: any = observer( setSelectedRows, collectionField, }; - const usePickActionProps = () => { - const { setVisible } = useActionContext(); - const { selectedRows, options, collectionField } = useContext(RecordPickerContext); - return { - onClick() { - const selectData = unionBy(selectedRows, options, collectionField?.targetKey || 'id'); - const data = field.value || []; - field.value = uniqBy(data.concat(selectData), collectionField?.targetKey || 'id'); - field.onInput(field.value); - setVisible(false); - }, - }; - }; const getFilter = () => { const targetKey = collectionField?.targetKey || 'id'; const list = options.map((option) => option[targetKey]).filter(Boolean); const filter = list.length ? { $and: [{ [`${targetKey}.$ne`]: list }] } : {}; return filter; }; + + const scope = useMemo(() => ({ + usePickActionProps, + useTableSelectorProps, + useCreateActionProps, + }), []); + return (
{ [run, params], ); + const scope = useMemo(() => ({ + useGridCardItemProps, + useGridCardActionBarProps, + }), []) + return ( toSchema(schema), [schema]); + const refresh = useCallback(() => { + ctx.refresh?.(); + props.onChange?.(s); + }, [s, ctx.refresh, props.onChange]); + + const contextValue = useMemo(() => ({ + ...ctx, + refresh + }), [ctx, refresh]); + return ( { - ctx.refresh?.(); - props.onChange?.(s); - }, - }} + value={contextValue} > @@ -53,7 +57,7 @@ const MemoizedSchemaComponent = (props: ISchemaFieldProps & SchemaComponentOnCha return ; }; -export const SchemaComponent = ( +export const SchemaComponent = memo(( props: (ISchemaFieldProps | IRecursionFieldProps) & { memoized?: boolean } & SchemaComponentOnChange, ) => { const { memoized, ...others } = props; @@ -61,4 +65,6 @@ export const SchemaComponent = ( return ; } return ; -}; +}); + +SchemaComponent.displayName = 'SchemaComponent'; diff --git a/packages/core/client/src/schema-component/core/SchemaComponentProvider.tsx b/packages/core/client/src/schema-component/core/SchemaComponentProvider.tsx index 39358a4e70..28fa7d1525 100644 --- a/packages/core/client/src/schema-component/core/SchemaComponentProvider.tsx +++ b/packages/core/client/src/schema-component/core/SchemaComponentProvider.tsx @@ -1,7 +1,7 @@ import { createForm } from '@formily/core'; import { FormProvider, Schema } from '@formily/react'; import { uid } from '@formily/shared'; -import React, { useMemo, useState } from 'react'; +import React, { useCallback, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { SchemaComponentContext } from '../context'; import { ISchemaComponentProvider } from '../types'; @@ -53,27 +53,35 @@ export const SchemaComponentProvider: React.FC = (prop }, [props.scope, t]); const [active, setActive] = useState(designable); - const schemaComponentContextValue = useMemo( - () => ({ + const refresh = useCallback(() => { + setUid(uid()); + }, []); + + const reset = useCallback(() => { + setFormId(uid()); + }, []); + const setDesignable = useCallback((value) => { + if (typeof designable !== 'boolean') { + setActive(value); + } + onDesignableChange?.(value); + }, [designable, onDesignableChange]); + + const contextValue = useMemo(() => { + return { scope, components, - reset: () => setFormId(uid()), - refresh: () => { - setUid(uid()); - }, + reset, + refresh, designable: typeof designable === 'boolean' ? designable : active, - setDesignable: (value) => { - if (typeof designable !== 'boolean') { - setActive(value); - } - onDesignableChange?.(value); - }, - }), - [uidValue, scope, components, designable, active], - ); + setDesignable, + }; + + // uidValue 虽然没用到,但是这里必须加上,为了让整个页面能够渲染 + }, [uidValue, scope, components, reset, refresh, designable, active, setDesignable]) return ( - + {children} diff --git a/packages/core/client/src/system-settings/SystemSettingsShortcut.tsx b/packages/core/client/src/system-settings/SystemSettingsShortcut.tsx index 6362f6f0ed..470cb8a148 100644 --- a/packages/core/client/src/system-settings/SystemSettingsShortcut.tsx +++ b/packages/core/client/src/system-settings/SystemSettingsShortcut.tsx @@ -2,7 +2,7 @@ import { ISchema, useForm } from '@formily/react'; import { uid } from '@formily/shared'; import { Card, message } from 'antd'; import cloneDeep from 'lodash/cloneDeep'; -import React from 'react'; +import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useSystemSettings } from '.'; import { i18n, useAPIClient, useRequest } from '..'; @@ -164,10 +164,11 @@ const schema: ISchema = { }; export const SystemSettingsPane = () => { + const scope = useMemo(() => ({ useSaveSystemSettingsValues, useSystemSettingsValues, useCloseAction }), []); return ( diff --git a/packages/plugins/@nocobase/plugin-import/src/client/ImportPluginProvider.tsx b/packages/plugins/@nocobase/plugin-import/src/client/ImportPluginProvider.tsx index 17e1133183..9f0146bd53 100644 --- a/packages/plugins/@nocobase/plugin-import/src/client/ImportPluginProvider.tsx +++ b/packages/plugins/@nocobase/plugin-import/src/client/ImportPluginProvider.tsx @@ -1,5 +1,5 @@ import { SchemaComponentOptions } from '@nocobase/client'; -import React, { useState } from 'react'; +import React, { memo, useMemo, useState } from 'react'; import { createPortal } from 'react-dom'; import { ImportActionInitializer, ImportDesigner } from '.'; import { ImportContext } from './context'; @@ -9,23 +9,30 @@ import { useShared } from './useShared'; export const ImportPluginProvider = (props: any) => { const { uploadValidator, beforeUploadHandler, validateUpload } = useShared(); + const scope = useMemo(() => ({ + uploadValidator, + validateUpload, + beforeUploadHandler, + useDownloadXlsxTemplateAction, + useImportStartAction, + }), [uploadValidator, beforeUploadHandler, validateUpload]) + + const components = useMemo(() => ({ + ImportActionInitializer, + ImportDesigner, + }), []); + return ( {props.children} ); }; -export const ImportContextProvider = (props: any) => { +export const ImportContextProvider = memo((props: any) => { const [importModalVisible, setImportModalVisible] = useState(false); const [importStatus, setImportStatus] = useState(ImportStatus.IMPORTING); const [importResult, setImportResult] = useState<{ @@ -47,4 +54,4 @@ export const ImportContextProvider = (props: any) => { {props.children} ); -}; +});