mirror of
https://github.com/nocobase/nocobase
synced 2024-11-16 01:17:43 +00:00
perf(BlockRequestProvider): prevent multiple re-renders of descendant components
This commit is contained in:
parent
261c2604c5
commit
1145721d48
@ -20,38 +20,37 @@ export interface CollectionRecordProviderProps<DataType = {}, ParentDataType = {
|
||||
parentRecord?: CollectionRecord<ParentDataType> | DataType;
|
||||
}
|
||||
|
||||
export const CollectionRecordProvider: FC<CollectionRecordProviderProps> = ({
|
||||
isNew,
|
||||
record,
|
||||
parentRecord,
|
||||
children,
|
||||
}) => {
|
||||
const parentRecordValue = useMemo(() => {
|
||||
if (parentRecord) {
|
||||
if (parentRecord instanceof CollectionRecord) return parentRecord;
|
||||
return new CollectionRecord({ data: parentRecord });
|
||||
}
|
||||
if (record instanceof CollectionRecord) return record.parentRecord;
|
||||
}, [parentRecord, record]);
|
||||
|
||||
const currentRecordValue = useMemo(() => {
|
||||
let res: CollectionRecord;
|
||||
if (record) {
|
||||
if (record instanceof CollectionRecord) {
|
||||
res = record;
|
||||
res.isNew = record.isNew || isNew;
|
||||
} else {
|
||||
res = new CollectionRecord({ data: record, isNew });
|
||||
export const CollectionRecordProvider: FC<CollectionRecordProviderProps> = React.memo(
|
||||
({ isNew, record, parentRecord, children }) => {
|
||||
const parentRecordValue = useMemo(() => {
|
||||
if (parentRecord) {
|
||||
if (parentRecord instanceof CollectionRecord) return parentRecord;
|
||||
return new CollectionRecord({ data: parentRecord });
|
||||
}
|
||||
} else {
|
||||
res = new CollectionRecord({ isNew });
|
||||
}
|
||||
res.setParentRecord(parentRecordValue);
|
||||
return res;
|
||||
}, [record, parentRecordValue, isNew]);
|
||||
if (record instanceof CollectionRecord) return record.parentRecord;
|
||||
}, [parentRecord, record]);
|
||||
|
||||
return <CollectionRecordContext.Provider value={currentRecordValue}>{children}</CollectionRecordContext.Provider>;
|
||||
};
|
||||
const currentRecordValue = useMemo(() => {
|
||||
let res: CollectionRecord;
|
||||
if (record) {
|
||||
if (record instanceof CollectionRecord) {
|
||||
res = record;
|
||||
res.isNew = record.isNew || isNew;
|
||||
} else {
|
||||
res = new CollectionRecord({ data: record, isNew });
|
||||
}
|
||||
} else {
|
||||
res = new CollectionRecord({ isNew });
|
||||
}
|
||||
res.setParentRecord(parentRecordValue);
|
||||
return res;
|
||||
}, [record, parentRecordValue, isNew]);
|
||||
|
||||
return <CollectionRecordContext.Provider value={currentRecordValue}>{children}</CollectionRecordContext.Provider>;
|
||||
},
|
||||
);
|
||||
|
||||
CollectionRecordProvider.displayName = 'CollectionRecordProvider';
|
||||
|
||||
export function useCollectionRecord<DataType = {}, ParentDataType = {}>(): CollectionRecord<DataType, ParentDataType> {
|
||||
const context = useContext<CollectionRecord<DataType, ParentDataType>>(CollectionRecordContext);
|
||||
|
@ -25,6 +25,8 @@ function useCurrentRequest<T>(options: Omit<AllDataBlockProps, 'type'>) {
|
||||
const dataLoadingMode = useDataLoadingMode();
|
||||
const resource = useDataBlockResource();
|
||||
const { action, params = {}, record, requestService, requestOptions } = options;
|
||||
const JSONParams = JSON.stringify(params);
|
||||
const JSONRecord = JSON.stringify(record);
|
||||
|
||||
const service = useMemo(() => {
|
||||
return (
|
||||
@ -47,13 +49,13 @@ function useCurrentRequest<T>(options: Omit<AllDataBlockProps, 'type'>) {
|
||||
return resource[action]?.({ ...paramsValue, ...customParams }).then((res) => res.data);
|
||||
})
|
||||
);
|
||||
}, [resource, action, JSON.stringify(params), JSON.stringify(record), requestService]);
|
||||
}, [resource, action, JSONParams, JSONRecord, requestService]);
|
||||
|
||||
const request = useRequest<T>(service, {
|
||||
...requestOptions,
|
||||
manual: dataLoadingMode === 'manual',
|
||||
ready: !!action,
|
||||
refreshDeps: [action, JSON.stringify(params), JSON.stringify(record), resource],
|
||||
refreshDeps: [action, JSONParams, JSONRecord, resource],
|
||||
});
|
||||
|
||||
return request;
|
||||
@ -100,6 +102,23 @@ function useParentRequest<T>(options: Omit<AllDataBlockProps, 'type'>) {
|
||||
);
|
||||
}
|
||||
|
||||
const EMPTY_REQUEST: UseRequestResult<{ data: any }> = Object.freeze({
|
||||
loading: true,
|
||||
data: { data: undefined },
|
||||
error: undefined,
|
||||
params: [],
|
||||
run: _.noop,
|
||||
runAsync: () => Promise.resolve({ data: undefined }),
|
||||
refresh: _.noop,
|
||||
refreshAsync: () => Promise.resolve({ data: undefined }),
|
||||
mutate: _.noop,
|
||||
cancel: _.noop,
|
||||
state: {
|
||||
data: { data: undefined },
|
||||
},
|
||||
setState: _.noop,
|
||||
});
|
||||
|
||||
export const BlockRequestProvider: FC = ({ children }) => {
|
||||
const props = useDataBlockProps();
|
||||
const {
|
||||
@ -115,7 +134,10 @@ export const BlockRequestProvider: FC = ({ children }) => {
|
||||
requestService,
|
||||
} = props;
|
||||
|
||||
const currentRequest = useCurrentRequest<{ data: any }>({
|
||||
let currentRequest = EMPTY_REQUEST,
|
||||
parentRequest = EMPTY_REQUEST;
|
||||
|
||||
const _currentRequest = useCurrentRequest<{ data: any }>({
|
||||
action,
|
||||
sourceId,
|
||||
record,
|
||||
@ -129,12 +151,18 @@ export const BlockRequestProvider: FC = ({ children }) => {
|
||||
},
|
||||
});
|
||||
|
||||
const parentRequest = useParentRequest<{ data: any }>({
|
||||
const _parentRequest = useParentRequest<{ data: any }>({
|
||||
sourceId,
|
||||
association,
|
||||
parentRecord,
|
||||
});
|
||||
|
||||
// This is to prevent multiple re-renders of descendant components
|
||||
if (!_currentRequest.loading && !_parentRequest.loading) {
|
||||
currentRequest = _currentRequest;
|
||||
parentRequest = _parentRequest;
|
||||
}
|
||||
|
||||
const memoizedParentRecord = useMemo(() => {
|
||||
return (
|
||||
parentRequest.data?.data &&
|
||||
|
Loading…
Reference in New Issue
Block a user