fix race condition
This commit is contained in:
@@ -116,26 +116,33 @@ const AppDetail: React.FC = () => {
|
||||
async (onSuccessCallback?: () => Promise<void> | void) => {
|
||||
if (!currentDomain || !selectedAppId) return undefined;
|
||||
|
||||
// Capture at request time to detect staleness after awaits
|
||||
const capturedDomainId = currentDomain.id;
|
||||
const capturedAppId = selectedAppId;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await window.api.getAppDetail({
|
||||
domainId: currentDomain.id,
|
||||
appId: selectedAppId,
|
||||
domainId: capturedDomainId,
|
||||
appId: capturedAppId,
|
||||
});
|
||||
|
||||
// Check if we're still on the same app and component is mounted before updating
|
||||
if (result.success) {
|
||||
setCurrentApp(result.data);
|
||||
// Store revision after callback to avoid being cleared by clearChanges
|
||||
const revision = result.data.customization?.revision;
|
||||
// Call the callback if provided
|
||||
// Guard: discard stale responses from previous domain/app switches
|
||||
const nowDomainId = useDomainStore.getState().currentDomain?.id;
|
||||
const nowAppId = useAppStore.getState().selectedAppId;
|
||||
if (nowDomainId !== capturedDomainId || nowAppId !== capturedAppId) return undefined;
|
||||
|
||||
if (onSuccessCallback) {
|
||||
await onSuccessCallback();
|
||||
}
|
||||
// Store the revision from Kintone API for remote change detection
|
||||
// Store revision after callback to avoid being cleared by clearChanges
|
||||
const revision = result.data.customization?.revision;
|
||||
setCurrentApp(result.data);
|
||||
// Must be AFTER callback since clearChanges() resets serverRevision to null
|
||||
if (revision && currentDomain) {
|
||||
fileChangeStore.setServerRevision(currentDomain.id, selectedAppId, revision);
|
||||
// Only update knownRevision when user explicitly refreshes or after deployment
|
||||
if (revision && shouldUpdateKnownRevision) {
|
||||
fileChangeStore.setServerRevision(capturedDomainId, capturedAppId, revision);
|
||||
}
|
||||
return result.data;
|
||||
}
|
||||
@@ -144,7 +151,13 @@ const AppDetail: React.FC = () => {
|
||||
console.error("Failed to load app detail:", error);
|
||||
return undefined;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
// Only reset loading if still on the same context; otherwise the new
|
||||
// request's loading state should not be cleared by this stale response.
|
||||
const nowDomainId = useDomainStore.getState().currentDomain?.id;
|
||||
const nowAppId = useAppStore.getState().selectedAppId;
|
||||
if (nowDomainId === capturedDomainId && nowAppId === capturedAppId) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
[currentDomain, selectedAppId, setCurrentApp, setLoading]
|
||||
@@ -160,6 +173,9 @@ const AppDetail: React.FC = () => {
|
||||
// Initialize file change store from Kintone data
|
||||
useEffect(() => {
|
||||
if (!currentApp || !currentDomain || !selectedAppId) return;
|
||||
// Guard against race condition: currentApp may be a stale response from a
|
||||
// previous app's request that resolved after selectedAppId already changed.
|
||||
if (String(currentApp.appId) !== String(selectedAppId)) return;
|
||||
|
||||
const customize = currentApp.customization;
|
||||
if (!customize) return;
|
||||
|
||||
@@ -88,23 +88,31 @@ const AppList: React.FC = () => {
|
||||
const handleLoadApps = async () => {
|
||||
if (!currentDomain) return;
|
||||
|
||||
const domainIdAtStart = currentDomain.id;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const result = await window.api.getApps({
|
||||
domainId: currentDomain.id,
|
||||
domainId: domainIdAtStart,
|
||||
});
|
||||
|
||||
// Discard result if domain switched during the request
|
||||
if (useDomainStore.getState().currentDomain?.id !== domainIdAtStart) return;
|
||||
|
||||
if (result.success) {
|
||||
setApps(result.data);
|
||||
} else {
|
||||
setError(result.error || t("loadAppsFailed"));
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : t("loadAppsFailed"));
|
||||
if (useDomainStore.getState().currentDomain?.id === domainIdAtStart) {
|
||||
setError(err instanceof Error ? err.message : t("loadAppsFailed"));
|
||||
}
|
||||
} finally {
|
||||
setLoading(false);
|
||||
if (useDomainStore.getState().currentDomain?.id === domainIdAtStart) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user