Skip to content

Commit 0f09003

Browse files
Copilothotlong
andcommitted
fix(plugin-view): prevent ObjectView.fetchData double-run caused by objectSchema dep
ObjectView's fetchData effect included `objectSchema` as a dependency. When `fetchObjectSchema` completed and set objectSchema state, React re-ran fetchData a second time — two calls to dataSource.find() per view activation. Both results were passed as `data` to child views (e.g., ObjectCalendar), causing the remaining 2× event duplication. Fix: use an objectSchemaRef (updated during render, same pattern as ObjectCalendar already uses) so fetchData reads the latest schema without requiring it in the dep array. Also adds handling for OData { value: [...] } response format that was missing from ObjectView's manual record extraction (extractRecords handles it; ObjectView didn't). Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent 92c02b8 commit 0f09003

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

packages/plugin-view/src/ObjectView.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* - ViewSwitcher for toggling between view types
2323
*/
2424

25-
import React, { useEffect, useState, useCallback, useMemo } from 'react';
25+
import React, { useEffect, useState, useCallback, useMemo, useRef } from 'react';
2626
import type {
2727
ObjectViewSchema,
2828
ObjectGridSchema,
@@ -219,6 +219,11 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
219219
onViewAction,
220220
}) => {
221221
const [objectSchema, setObjectSchema] = useState<Record<string, unknown> | null>(null);
222+
// Assigned in the render body (not in an effect) so the fetchData effect always
223+
// reads the latest objectSchema without needing it as a dependency. This matches
224+
// the same pattern used in ObjectCalendar's objectSchemaRef.
225+
const objectSchemaRef = useRef<Record<string, unknown> | null>(null);
226+
objectSchemaRef.current = objectSchema;
222227
const [isFormOpen, setIsFormOpen] = useState(false);
223228
const [formMode, setFormMode] = useState<FormMode>('create');
224229
const [selectedRecord, setSelectedRecord] = useState<Record<string, unknown> | null>(null);
@@ -322,8 +327,11 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
322327
? sortConfig.map(s => ({ field: s.field, order: s.direction }))
323328
: (currentNamedViewConfig?.sort || activeView?.sort || schema.table?.defaultSort || undefined);
324329

325-
// Auto-inject $expand for lookup/master_detail fields
326-
const expand = buildExpandFields((objectSchema as any)?.fields);
330+
// Auto-inject $expand for lookup/master_detail fields.
331+
// Use a ref instead of the state variable to avoid re-running this effect
332+
// every time the object schema loads — that would cause a double-fetch and
333+
// duplicate events in child views like the calendar.
334+
const expand = buildExpandFields((objectSchemaRef.current as any)?.fields);
327335
const results = await dataSource.find(schema.objectName, {
328336
$filter: finalFilter.length > 0 ? finalFilter : undefined,
329337
$orderby: sort,
@@ -339,6 +347,8 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
339347
items = (results as any).data;
340348
} else if (Array.isArray((results as any).records)) {
341349
items = (results as any).records;
350+
} else if (Array.isArray((results as any).value)) {
351+
items = (results as any).value;
342352
}
343353
}
344354

@@ -352,8 +362,9 @@ export const ObjectView: React.FC<ObjectViewProps> = ({
352362

353363
fetchData();
354364
return () => { isMounted = false; };
365+
// objectSchema intentionally omitted from deps — read via ref to prevent double-fetch
355366
// eslint-disable-next-line react-hooks/exhaustive-deps
356-
}, [schema.objectName, dataSource, currentViewType, filterValues, sortConfig, refreshKey, currentNamedViewConfig, activeView, renderListView, objectSchema]);
367+
}, [schema.objectName, dataSource, currentViewType, filterValues, sortConfig, refreshKey, currentNamedViewConfig, activeView, renderListView]);
357368

358369
// Determine layout mode
359370
const layout = schema.layout || 'drawer';

0 commit comments

Comments
 (0)