refactor: lazy load document content only when its tab is active and separate content state reset logic
This commit is contained in:
@@ -101,50 +101,7 @@ const DocumentInfoPanel: React.FC<DocumentInfoPanelProps> = ({
|
|||||||
return { status: 'idle', data: null, error: null };
|
return { status: 'idle', data: null, error: null };
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!contentConfig || !showContentTab) {
|
|
||||||
setContentState(null);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!contentEnabled || !loadContent) {
|
|
||||||
setContentState({ status: contentEnabled ? 'idle' : 'unavailable', data: null, error: null });
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
let cancelled = false;
|
|
||||||
const controller = new AbortController();
|
|
||||||
|
|
||||||
setContentState({ status: 'loading', data: null, error: null });
|
|
||||||
|
|
||||||
Promise.resolve(loadContent({ signal: controller.signal }))
|
|
||||||
.then((result) => {
|
|
||||||
if (cancelled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (result && result.length) {
|
|
||||||
setContentState({ status: 'loaded', data: result, error: null });
|
|
||||||
} else {
|
|
||||||
setContentState({ status: 'empty', data: '', error: null });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
if (cancelled || error?.name === 'AbortError') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setContentState({
|
|
||||||
status: 'error',
|
|
||||||
data: null,
|
|
||||||
error,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
cancelled = true;
|
|
||||||
controller.abort();
|
|
||||||
contentConfig.onCancel?.();
|
|
||||||
};
|
|
||||||
}, [contentConfig, contentEnabled, showContentTab, document?.id, resetKey, loadContent]);
|
|
||||||
|
|
||||||
const renderSummarySection = useCallback(() => (
|
const renderSummarySection = useCallback(() => (
|
||||||
<DocumentSummarySection
|
<DocumentSummarySection
|
||||||
@@ -373,6 +330,92 @@ const DocumentInfoPanel: React.FC<DocumentInfoPanelProps> = ({
|
|||||||
|
|
||||||
const activeTabId = isControlled ? controlledActiveTab : uncontrolledTab;
|
const activeTabId = isControlled ? controlledActiveTab : uncontrolledTab;
|
||||||
|
|
||||||
|
// Track previous ID/key to avoid unnecessary resets on prop reference changes
|
||||||
|
const prevDocIdRef = React.useRef(document?.id);
|
||||||
|
const prevResetKeyRef = React.useRef(resetKey);
|
||||||
|
|
||||||
|
// Reset content state when document changes
|
||||||
|
useEffect(() => {
|
||||||
|
const docIdChanged = prevDocIdRef.current !== document?.id;
|
||||||
|
const resetKeyChanged = prevResetKeyRef.current !== resetKey;
|
||||||
|
|
||||||
|
if (docIdChanged || resetKeyChanged) {
|
||||||
|
prevDocIdRef.current = document?.id;
|
||||||
|
prevResetKeyRef.current = resetKey;
|
||||||
|
|
||||||
|
if (!contentConfig || !showContentTab) {
|
||||||
|
setContentState(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!contentEnabled || !loadContent) {
|
||||||
|
setContentState({ status: contentEnabled ? 'idle' : 'unavailable', data: null, error: null });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reset to idle so the loading effect can trigger if needed
|
||||||
|
setContentState({ status: 'idle', data: null, error: null });
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
contentConfig,
|
||||||
|
showContentTab,
|
||||||
|
contentEnabled,
|
||||||
|
loadContent,
|
||||||
|
document?.id,
|
||||||
|
resetKey,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Lazy load content when tab is active
|
||||||
|
useEffect(() => {
|
||||||
|
const contentTabId = contentConfig?.id || 'content';
|
||||||
|
const isActive = activeTabId === contentTabId;
|
||||||
|
|
||||||
|
if (!isActive || !contentConfig || !loadContent || !contentEnabled) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentState?.status !== 'idle') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let cancelled = false;
|
||||||
|
const controller = new AbortController();
|
||||||
|
|
||||||
|
setContentState({ status: 'loading', data: null, error: null });
|
||||||
|
|
||||||
|
Promise.resolve(loadContent({ signal: controller.signal }))
|
||||||
|
.then((result) => {
|
||||||
|
if (cancelled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result && result.length) {
|
||||||
|
setContentState({ status: 'loaded', data: result, error: null });
|
||||||
|
} else {
|
||||||
|
setContentState({ status: 'empty', data: '', error: null });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
if (cancelled || error?.name === 'AbortError') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setContentState({
|
||||||
|
status: 'error',
|
||||||
|
data: null,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
controller.abort();
|
||||||
|
contentConfig.onCancel?.();
|
||||||
|
};
|
||||||
|
}, [
|
||||||
|
activeTabId,
|
||||||
|
contentConfig,
|
||||||
|
loadContent,
|
||||||
|
contentEnabled,
|
||||||
|
contentState?.status,
|
||||||
|
]);
|
||||||
|
|
||||||
const handleTabSelect = (tabId) => {
|
const handleTabSelect = (tabId) => {
|
||||||
if (!visibleTabs.some((tab) => tab.id === tabId)) {
|
if (!visibleTabs.some((tab) => tab.id === tabId)) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user