Skip to content

Commit 2ba1103

Browse files
committed
Use AbortController and get rid of double-RAF
1 parent f843b3b commit 2ba1103

2 files changed

Lines changed: 29 additions & 17 deletions

File tree

internal/web/ui/src/features/component/AsyncStringifiedValue.tsx

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,27 +92,26 @@ const AsyncLargeValue = ({ value }: { value: Value }) => {
9292
useEffect(() => {
9393
let cancelled = false;
9494

95-
// Use double-RAF to ensure the loading state is painted before blocking work starts
96-
requestAnimationFrame(() => {
95+
// Use setTimeout to defer blocking work to a macrotask, allowing React to
96+
// commit and paint the loading state first
97+
const timeoutId = setTimeout(() => {
9798
if (cancelled) return;
98-
requestAnimationFrame(() => {
99-
if (cancelled) return;
100-
101-
try {
102-
const result = alloyStringify(value);
103-
if (!cancelled) {
104-
setState({ status: 'ready', result });
105-
}
106-
} catch {
107-
if (!cancelled) {
108-
setState({ status: 'ready', result: '[Error stringifying value]' });
109-
}
99+
100+
try {
101+
const result = alloyStringify(value);
102+
if (!cancelled) {
103+
setState({ status: 'ready', result });
104+
}
105+
} catch {
106+
if (!cancelled) {
107+
setState({ status: 'ready', result: '[Error stringifying value]' });
110108
}
111-
});
112-
});
109+
}
110+
}, 0);
113111

114112
return () => {
115113
cancelled = true;
114+
clearTimeout(timeoutId);
116115
};
117116
}, [value]);
118117

internal/web/ui/src/pages/ComponentDetailPage.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const ComponentDetailPage: FC = () => {
4141
return;
4242
}
4343

44+
const abortController = new AbortController();
4445
const fetchURL = `./api/v0/web/components/${id}`;
4546
setLoadingEndpoint(fetchURL);
4647

@@ -49,6 +50,7 @@ const ComponentDetailPage: FC = () => {
4950
const resp = await fetch(fetchURL, {
5051
cache: 'no-cache',
5152
credentials: 'same-origin',
53+
signal: abortController.signal,
5254
});
5355
const data: ComponentDetail = await resp.json();
5456

@@ -58,6 +60,7 @@ const ComponentDetailPage: FC = () => {
5860
const moduleComponentsResp = await fetch(modulesURL, {
5961
cache: 'no-cache',
6062
credentials: 'same-origin',
63+
signal: abortController.signal,
6164
});
6265
const moduleComponents = (await moduleComponentsResp.json()) as ComponentInfo[];
6366

@@ -68,7 +71,17 @@ const ComponentDetailPage: FC = () => {
6871
setLoadingEndpoint(null);
6972
};
7073

71-
worker().catch(console.error);
74+
worker().catch((err) => {
75+
// Ignore abort errors - these are expected when the effect cleans up
76+
if (err instanceof Error && err.name === 'AbortError') {
77+
return;
78+
}
79+
console.error(err);
80+
});
81+
82+
return () => {
83+
abortController.abort();
84+
};
7285
},
7386
[id]
7487
);

0 commit comments

Comments
 (0)