refactor: improve FixedBlock performance (#1593)

* refactor:  improve FixedBlock performance

* fix: style

* fix: fixedBlock not work when the page have many blocks

* refactor: improve performance
This commit is contained in:
Dunqing 2023-03-29 17:11:20 +08:00 committed by GitHub
parent e6326460b0
commit 6747331529
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 145 additions and 150 deletions

View File

@ -1,7 +1,7 @@
import { ArrayField } from '@formily/core';
import { useField } from '@formily/react';
import React, { createContext, useContext, useEffect } from 'react';
import { useFixedSchema } from '../schema-component';
import { FixedBlockWrapper } from '../schema-component';
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
export const CalendarBlockContext = createContext<any>({});
@ -10,23 +10,24 @@ const InternalCalendarBlockProvider = (props) => {
const { fieldNames, showLunar } = props;
const field = useField();
const { resource, service } = useBlockRequestContext();
const fixedBlock = useFixedSchema()
// if (service.loading) {
// return <Spin />;
// }
return (
<CalendarBlockContext.Provider
value={{
field,
service,
resource,
fieldNames,
showLunar,
fixedBlock,
}}
>
{props.children}
</CalendarBlockContext.Provider>
<FixedBlockWrapper>
<CalendarBlockContext.Provider
value={{
field,
service,
resource,
fieldNames,
showLunar,
fixedBlock: field?.decoratorProps?.fixedBlock,
}}
>
{props.children}
</CalendarBlockContext.Provider>
</FixedBlockWrapper>
);
};
@ -53,6 +54,6 @@ export const useCalendarBlockProps = () => {
return {
fieldNames: ctx.fieldNames,
showLunar: ctx.showLunar,
fixedBlock: ctx.fixedBlock
fixedBlock: ctx.fixedBlock,
};
};

View File

@ -5,7 +5,7 @@ import uniq from 'lodash/uniq';
import React, { createContext, useContext, useEffect } from 'react';
import { useACLRoleContext } from '../acl';
import { useCollection, useCollectionManager } from '../collection-manager';
import { useFixedSchema } from '../schema-component';
import { FixedBlockWrapper } from '../schema-component';
import { toColumns } from '../schema-component/antd/kanban/Kanban';
import { BlockProvider, useBlockRequestContext } from './BlockProvider';
@ -24,7 +24,6 @@ const useGroupField = (props) => {
const InternalKanbanBlockProvider = (props) => {
const field = useField<any>();
const fixedBlock = useFixedSchema();
const { resource, service } = useBlockRequestContext();
const groupField = useGroupField(props);
if (!groupField) {
@ -35,20 +34,22 @@ const InternalKanbanBlockProvider = (props) => {
}
field.loaded = true;
return (
<KanbanBlockContext.Provider
value={{
props: {
resource: props.resource,
},
field,
service,
resource,
groupField,
fixedBlock,
}}
>
{props.children}
</KanbanBlockContext.Provider>
<FixedBlockWrapper>
<KanbanBlockContext.Provider
value={{
props: {
resource: props.resource,
},
field,
service,
resource,
groupField,
fixedBlock: field?.decoratorProps?.fixedBlock,
}}
>
{props.children}
</KanbanBlockContext.Provider>
</FixedBlockWrapper>
);
};

View File

@ -3,7 +3,7 @@ import { FormContext, Schema, useField, useFieldSchema } from '@formily/react';
import uniq from 'lodash/uniq';
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { useCollectionManager } from '../collection-manager';
import { SchemaComponentOptions, useFixedSchema, removeNullCondition } from '../schema-component';
import { SchemaComponentOptions, removeNullCondition, FixedBlockWrapper } from '../schema-component';
import { BlockProvider, RenderChildrenWithAssociationFilter, useBlockRequestContext } from './BlockProvider';
import { useFilterBlock } from '../filter-provider/FilterProvider';
import { findFilterTargets } from './hooks';
@ -24,24 +24,25 @@ const InternalTableBlockProvider = (props: Props) => {
const field = useField();
const { resource, service } = useBlockRequestContext();
const [expandFlag, setExpandFlag] = useState(false);
useFixedSchema();
return (
<TableBlockContext.Provider
value={{
field,
service,
resource,
params,
showIndex,
dragSort,
rowKey,
expandFlag,
childrenColumnName,
setExpandFlag: () => setExpandFlag(!expandFlag),
}}
>
<RenderChildrenWithAssociationFilter {...props} />
</TableBlockContext.Provider>
<FixedBlockWrapper>
<TableBlockContext.Provider
value={{
field,
service,
resource,
params,
showIndex,
dragSort,
rowKey,
expandFlag,
childrenColumnName,
setExpandFlag: () => setExpandFlag(!expandFlag),
}}
>
<RenderChildrenWithAssociationFilter {...props} />
</TableBlockContext.Provider>
</FixedBlockWrapper>
);
};

View File

@ -20,6 +20,9 @@ const divWrap = (schema: ISchema) => {
return {
type: 'void',
'x-component': 'div',
'x-component-props': {
className: 'nb-block-wrap',
},
properties: {
[schema.name || uid()]: schema,
},

View File

@ -1,51 +1,58 @@
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
import { useField, useFieldSchema } from '@formily/react';
import { css } from '@emotion/css';
import { SchemaSettings } from '../../../schema-settings';
import { useTranslation } from 'react-i18next';
import { useDesignable } from '../../hooks';
import { useRecord } from '../../../record-provider';
import { useBlockTemplateContext } from '../../../schema-templates/BlockTemplate';
const FixedBlockContext = React.createContext({
setFixedSchema: (schema: Schema) => {},
const FixedBlockContext = React.createContext<{
setFixedBlock: (value: string | false) => void;
height: number;
fixedBlockUID: boolean | string;
}>({
setFixedBlock: () => {},
height: 0,
fixedSchemaRef: {} as unknown as React.MutableRefObject<Schema>,
fixedBlockUID: false,
});
export const useFixedSchema = () => {
const field = useField();
const fieldSchema = useFieldSchema();
const { setFixedSchema, fixedSchemaRef } = useFixedBlock();
const { fieldSchema: templateFieldSchema } = useBlockTemplateContext();
const { setFixedBlock, fixedBlockUID } = useFixedBlock();
const hasSet = useRef(false);
useEffect(() => {
if (fieldSchema?.['x-decorator-props']?.fixedBlock) {
const nextSchema = templateFieldSchema || fieldSchema;
setFixedSchema(nextSchema);
if (!fixedBlockUID || hasSet.current) {
setFixedBlock(field?.decoratorProps?.fixedBlock ? fieldSchema['x-uid'] : false);
hasSet.current = true;
} else if (hasSet.current) {
setFixedSchema(null);
}
}, [field?.decoratorProps?.fixedBlock, fieldSchema?.['x-decorator-props']?.fixedBlock]);
}, [field?.decoratorProps?.fixedBlock]);
useEffect(
() => () => {
if (hasSet.current && fixedSchemaRef.current) {
setFixedSchema(null);
fixedSchemaRef.current = null;
}
},
[],
);
return fieldSchema?.['x-decorator-props']?.fixedBlock
return fieldSchema['x-uid'] === fixedBlockUID;
};
export const useFixedBlock = () => {
return useContext(FixedBlockContext);
};
export const FixedBlockWrapper: React.FC = (props) => {
const fixedBlock = useFixedSchema();
const { height, fixedBlockUID } = useFixedBlock();
// The fixedBlockUID of false means that the page has no fixed blocks
if (!fixedBlock && fixedBlockUID) return null;
return (
<div
className="nb-fixed-block"
style={{
height: fixedBlockUID !== false ? `calc(100vh - ${height}px)` : undefined,
}}
>
{props.children}
</div>
);
};
export const useFixedBlockDesignerSetting = () => {
const field = useField();
const { t } = useTranslation();
@ -83,56 +90,39 @@ interface FixedBlockProps {
height: number;
}
const fixedBlockCss = css`
overflow: hidden;
position: relative;
.noco-card-item {
height: 100%;
.ant-card {
display: flex;
flex-direction: column;
height: 100%;
.ant-card-body {
height: 1px;
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
}
}
`;
const FixedBlock: React.FC<FixedBlockProps> = (props) => {
const { height } = props;
const [fixedSchema, _setFixedSchema] = useState<Schema>();
const fixedSchemaRef = useRef(fixedSchema);
const setFixedSchema = (next) => {
if (fixedSchema && next) {
fixedSchemaRef.current = next;
}
_setFixedSchema(next);
};
const schema = useMemo<Schema>(() => {
return fixedSchema?.parent;
}, [fixedSchema]);
const [fixedBlockUID, setFixedBlock] = useState<false | string>(false);
return (
<FixedBlockContext.Provider value={{ height, setFixedSchema, fixedSchemaRef }}>
{schema ? (
<div
className={css`
overflow: hidden;
position: relative;
height: calc(100vh - ${height}px);
.noco-card-item {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
.ant-card {
display: flex;
flex-direction: column;
height: 100%;
.ant-card-body {
height: 1px;
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
}
}
`}
>
<RecursionField onlyRenderProperties={false} name={schema.name} schema={schema} />
</div>
) : (
props.children
)}
<FixedBlockContext.Provider value={{ height, setFixedBlock, fixedBlockUID }}>
<div
className={fixedBlockUID ? fixedBlockCss : ''}
style={{
height: fixedBlockUID ? `calc(100vh - ${height}px)` : undefined,
}}
>
{props.children}
</div>
</FixedBlockContext.Provider>
);
};

View File

@ -111,13 +111,22 @@ const pageDesignerCss = css`
}
`;
const pageWithFixedBlockCss = classNames([
'nb-page',
css`
> .nb-grid:not(:last-child) {
> .nb-schema-initializer-button {
display: none;
}
}
`,
]);
export const Page = (props) => {
const { children, ...others } = props;
const field = useField();
const compile = useCompile();
const { title, setTitle } = useDocumentTitle();
const fieldSchema = useFieldSchema();
const history = useHistory();
const dn = useDesignable();
useEffect(() => {
if (!title) {
@ -288,17 +297,7 @@ export const Page = (props) => {
height + 46 + 48
}
>
<div
className={css`
> .nb-grid:not(:last-child) {
> .nb-schema-initializer-button {
display: none;
}
}
`}
>
{props.children}
</div>
<div className={pageWithFixedBlockCss}>{props.children}</div>
</FixedBlock>
)}
</div>

View File

@ -1,6 +1,5 @@
import { ArrayField } from '@formily/core';
import { useField, useFieldSchema } from '@formily/react';
import { BlockProvider, SchemaComponentOptions, useBlockRequestContext, useFixedSchema } from '@nocobase/client';
import { BlockProvider, FixedBlockWrapper, SchemaComponentOptions, useBlockRequestContext } from '@nocobase/client';
import React, { createContext, useContext, useEffect, useState } from 'react';
export const MapBlockContext = createContext<any>({});
@ -12,23 +11,24 @@ const InternalMapBlockProvider = (props) => {
const { resource, service } = useBlockRequestContext();
const [selectedRecordKeys, setSelectedRecordKeys] = useState([]);
useFixedSchema();
return (
<SchemaComponentOptions scope={{ selectedRecordKeys }}>
<MapBlockContext.Provider
value={{
field,
service,
resource,
fieldNames,
fixedBlock: fieldSchema?.['x-decorator-props']?.fixedBlock,
selectedRecordKeys,
setSelectedRecordKeys,
}}
>
{props.children}
</MapBlockContext.Provider>
</SchemaComponentOptions>
<FixedBlockWrapper>
<SchemaComponentOptions scope={{ selectedRecordKeys }}>
<MapBlockContext.Provider
value={{
field,
service,
resource,
fieldNames,
fixedBlock: fieldSchema?.['x-decorator-props']?.fixedBlock,
selectedRecordKeys,
setSelectedRecordKeys,
}}
>
{props.children}
</MapBlockContext.Provider>
</SchemaComponentOptions>
</FixedBlockWrapper>
);
};