mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 06:46:38 +00:00
fix: schema component options add memo
This commit is contained in:
parent
55d055f801
commit
2c3a04c5c1
@ -29,15 +29,20 @@ export const ScopeSelect = (props) => {
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
const scope = useMemo(() => {
|
||||
return {
|
||||
onChange(value) {
|
||||
props?.onChange?.(value);
|
||||
},
|
||||
};
|
||||
}, [props?.onChange])
|
||||
|
||||
return (
|
||||
<FormProvider form={form}>
|
||||
<SchemaComponent
|
||||
components={{ RolesResourcesScopesSelectedRowKeysProvider }}
|
||||
scope={{
|
||||
onChange(value) {
|
||||
props?.onChange?.(value);
|
||||
},
|
||||
}}
|
||||
scope={scope}
|
||||
schema={scopesSchema}
|
||||
/>
|
||||
</FormProvider>
|
||||
|
@ -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 (
|
||||
<SchemaComponentOptions
|
||||
components={{
|
||||
TableFieldProvider,
|
||||
TableBlockProvider,
|
||||
TableSelectorProvider,
|
||||
FormBlockProvider,
|
||||
FilterFormBlockProvider,
|
||||
FormFieldProvider,
|
||||
DetailsBlockProvider,
|
||||
RecordLink,
|
||||
}}
|
||||
scope={{
|
||||
...bp,
|
||||
useSourceIdFromRecord,
|
||||
useSourceIdFromParentRecord,
|
||||
useParamsFromRecord,
|
||||
useFormBlockProps,
|
||||
useFormFieldProps,
|
||||
useDetailsBlockProps,
|
||||
useTableFieldProps,
|
||||
useTableBlockProps,
|
||||
useTableSelectorProps,
|
||||
}}
|
||||
components={components}
|
||||
scope={scope}
|
||||
>
|
||||
{props.children}
|
||||
</SchemaComponentOptions>
|
||||
|
@ -111,8 +111,9 @@ export const TableBlockProvider = (props) => {
|
||||
};
|
||||
}, [parsedFilter, params]);
|
||||
|
||||
const scope = useMemo(() => ({ treeTable }), [treeTable]);
|
||||
return (
|
||||
<SchemaComponentOptions scope={{ treeTable }}>
|
||||
<SchemaComponentOptions scope={scope}>
|
||||
<FormContext.Provider value={form}>
|
||||
<BlockProvider name={props.name || 'table'} {...props} params={paramsWithFilter} runWhenParamsChanged>
|
||||
<InternalTableBlockProvider {...props} childrenColumnName={childrenColumnName} params={paramsWithFilter} />
|
||||
|
@ -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 (
|
||||
<SchemaComponentOptions scope={{ treeTable }}>
|
||||
<SchemaComponentOptions scope={scope}>
|
||||
<BlockProvider name="table-selector" {...props} params={params}>
|
||||
<InternalTableSelectorProvider {...props} params={params} extraFilter={extraFilter} />
|
||||
</BlockProvider>
|
||||
|
@ -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 (
|
||||
<SchemaComponentOptions scope={{ useChinaRegionDataSource, useChinaRegionLoadData }}>
|
||||
<SchemaComponentOptions scope={scope}>
|
||||
{props.children}
|
||||
</SchemaComponentOptions>
|
||||
);
|
||||
|
@ -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 (
|
||||
<RecordProvider record={record}>
|
||||
<ActionContextProvider value={{ visible, setVisible }}>
|
||||
@ -192,16 +195,8 @@ export const AddCollectionAction = (props) => {
|
||||
</Dropdown>
|
||||
<SchemaComponent
|
||||
schema={schema}
|
||||
components={{ ...components, ArrayTable, TemplateSummay: TemplateSummary }}
|
||||
scope={{
|
||||
getContainer,
|
||||
useCancelAction,
|
||||
createOnly: true,
|
||||
useCreateCollection,
|
||||
record,
|
||||
showReverseFieldConfig: true,
|
||||
...scope,
|
||||
}}
|
||||
components={components}
|
||||
scope={scopes}
|
||||
/>
|
||||
</ActionContextProvider>
|
||||
</RecordProvider>
|
||||
|
@ -199,12 +199,19 @@ const MenuEditor = (props) => {
|
||||
},
|
||||
);
|
||||
|
||||
const scope = useMemo(() => ({
|
||||
useMenuProps,
|
||||
onSelect,
|
||||
sideMenuRef,
|
||||
defaultSelectedUid
|
||||
}), [])
|
||||
|
||||
if (loading) {
|
||||
return render();
|
||||
}
|
||||
return (
|
||||
<SchemaIdContext.Provider value={defaultSelectedUid}>
|
||||
<SchemaComponent memoized scope={{ useMenuProps, onSelect, sideMenuRef, defaultSelectedUid }} schema={schema} />
|
||||
<SchemaComponent memoized scope={scope} schema={schema} />
|
||||
</SchemaIdContext.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -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<ArrayField>();
|
||||
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 (
|
||||
<div
|
||||
className={css`
|
||||
@ -217,11 +227,7 @@ export const SubTable: any = observer(
|
||||
<FormProvider>
|
||||
<TableSelectorParamsProvider params={{ filter: getFilter() }}>
|
||||
<SchemaComponentOptions
|
||||
scope={{
|
||||
usePickActionProps,
|
||||
useTableSelectorProps,
|
||||
useCreateActionProps,
|
||||
}}
|
||||
scope={scope}
|
||||
>
|
||||
<RecursionField
|
||||
onlyRenderProperties
|
||||
|
@ -2,7 +2,7 @@ import { css, cx } from '@emotion/css';
|
||||
import { ArrayField } from '@formily/core';
|
||||
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||
import { List as AntdList, Col, PaginationProps } from 'antd';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { SortableItem } from '../../common';
|
||||
import { SchemaComponentOptions } from '../../core';
|
||||
import { useDesigner, useProps } from '../../hooks';
|
||||
@ -96,12 +96,14 @@ const InternalGridCard = (props) => {
|
||||
[run, params],
|
||||
);
|
||||
|
||||
const scope = useMemo(() => ({
|
||||
useGridCardItemProps,
|
||||
useGridCardActionBarProps,
|
||||
}), [])
|
||||
|
||||
return (
|
||||
<SchemaComponentOptions
|
||||
scope={{
|
||||
useGridCardItemProps,
|
||||
useGridCardActionBarProps,
|
||||
}}
|
||||
scope={scope}
|
||||
>
|
||||
<SortableItem className={cx('nb-card-list', designerCss)}>
|
||||
<AntdList
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { IRecursionFieldProps, ISchemaFieldProps, RecursionField, Schema } from '@formily/react';
|
||||
import React, { useContext, useMemo } from 'react';
|
||||
import React, { memo, useCallback, useContext, useMemo } from 'react';
|
||||
import { SchemaComponentContext } from '../context';
|
||||
import { SchemaComponentOptions } from './SchemaComponentOptions';
|
||||
|
||||
@ -30,15 +30,19 @@ const RecursionSchemaComponent = (props: ISchemaFieldProps & SchemaComponentOnCh
|
||||
const { components, scope, schema, ...others } = props;
|
||||
const ctx = useContext(SchemaComponentContext);
|
||||
const s = useMemo(() => toSchema(schema), [schema]);
|
||||
const refresh = useCallback(() => {
|
||||
ctx.refresh?.();
|
||||
props.onChange?.(s);
|
||||
}, [s, ctx.refresh, props.onChange]);
|
||||
|
||||
const contextValue = useMemo(() => ({
|
||||
...ctx,
|
||||
refresh
|
||||
}), [ctx, refresh]);
|
||||
|
||||
return (
|
||||
<SchemaComponentContext.Provider
|
||||
value={{
|
||||
...ctx,
|
||||
refresh: () => {
|
||||
ctx.refresh?.();
|
||||
props.onChange?.(s);
|
||||
},
|
||||
}}
|
||||
value={contextValue}
|
||||
>
|
||||
<SchemaComponentOptions inherit components={components} scope={scope}>
|
||||
<RecursionField {...others} schema={s} />
|
||||
@ -53,7 +57,7 @@ const MemoizedSchemaComponent = (props: ISchemaFieldProps & SchemaComponentOnCha
|
||||
return <RecursionSchemaComponent {...others} schema={s} />;
|
||||
};
|
||||
|
||||
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 <MemoizedSchemaComponent {...others} />;
|
||||
}
|
||||
return <RecursionSchemaComponent {...others} />;
|
||||
};
|
||||
});
|
||||
|
||||
SchemaComponent.displayName = 'SchemaComponent';
|
||||
|
@ -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<ISchemaComponentProvider> = (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 (
|
||||
<SchemaComponentContext.Provider value={schemaComponentContextValue}>
|
||||
<SchemaComponentContext.Provider value={contextValue}>
|
||||
<FormProvider form={form}>
|
||||
<SchemaComponentOptions inherit scope={scope} components={components}>
|
||||
{children}
|
||||
|
@ -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 (
|
||||
<Card bordered={false}>
|
||||
<SchemaComponent
|
||||
scope={{ useSaveSystemSettingsValues, useSystemSettingsValues, useCloseAction }}
|
||||
scope={scope}
|
||||
schema={schema}
|
||||
/>
|
||||
</Card>
|
||||
|
@ -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 (
|
||||
<SchemaComponentOptions
|
||||
components={{ ImportActionInitializer, ImportDesigner }}
|
||||
scope={{
|
||||
uploadValidator,
|
||||
validateUpload,
|
||||
beforeUploadHandler,
|
||||
useDownloadXlsxTemplateAction,
|
||||
useImportStartAction,
|
||||
}}
|
||||
components={components}
|
||||
scope={scope}
|
||||
>
|
||||
<ImportContextProvider>{props.children}</ImportContextProvider>
|
||||
</SchemaComponentOptions>
|
||||
);
|
||||
};
|
||||
|
||||
export const ImportContextProvider = (props: any) => {
|
||||
export const ImportContextProvider = memo((props: any) => {
|
||||
const [importModalVisible, setImportModalVisible] = useState(false);
|
||||
const [importStatus, setImportStatus] = useState<number>(ImportStatus.IMPORTING);
|
||||
const [importResult, setImportResult] = useState<{
|
||||
@ -47,4 +54,4 @@ export const ImportContextProvider = (props: any) => {
|
||||
{props.children}
|
||||
</ImportContext.Provider>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user