mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-04 11:43:57 +08:00
Fix race condition in useEffect hooks and type assertion bug (#2827)
- Add active flag pattern to 3 useEffect hooks in App.tsx to prevent event listener leaks when component unmounts before async setup completes - Add guard check in useSettings.ts to prevent undefined from being stored in localStorage when payload.language is missing Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+26
-5
@@ -333,34 +333,42 @@ function App() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let unsubscribe: (() => void) | undefined;
|
let unsubscribe: (() => void) | undefined;
|
||||||
|
let active = true;
|
||||||
|
|
||||||
const setupListener = async () => {
|
const setupListener = async () => {
|
||||||
try {
|
try {
|
||||||
unsubscribe = await providersApi.onSwitched(
|
const off = await providersApi.onSwitched(
|
||||||
async (event: ProviderSwitchEvent) => {
|
async (event: ProviderSwitchEvent) => {
|
||||||
if (event.appType === activeApp) {
|
if (event.appType === activeApp) {
|
||||||
await refetch();
|
await refetch();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if (!active) {
|
||||||
|
off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsubscribe = off;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[App] Failed to subscribe provider switch event", error);
|
console.error("[App] Failed to subscribe provider switch event", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setupListener();
|
void setupListener();
|
||||||
return () => {
|
return () => {
|
||||||
|
active = false;
|
||||||
unsubscribe?.();
|
unsubscribe?.();
|
||||||
};
|
};
|
||||||
}, [activeApp, refetch]);
|
}, [activeApp, refetch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let unsubscribe: (() => void) | undefined;
|
let unsubscribe: (() => void) | undefined;
|
||||||
|
let active = true;
|
||||||
|
|
||||||
const setupListener = async () => {
|
const setupListener = async () => {
|
||||||
try {
|
try {
|
||||||
const { listen } = await import("@tauri-apps/api/event");
|
const { listen } = await import("@tauri-apps/api/event");
|
||||||
unsubscribe = await listen("universal-provider-synced", async () => {
|
const off = await listen("universal-provider-synced", async () => {
|
||||||
await queryClient.invalidateQueries({ queryKey: ["providers"] });
|
await queryClient.invalidateQueries({ queryKey: ["providers"] });
|
||||||
try {
|
try {
|
||||||
await providersApi.updateTrayMenu();
|
await providersApi.updateTrayMenu();
|
||||||
@@ -368,6 +376,11 @@ function App() {
|
|||||||
console.error("[App] Failed to update tray menu", error);
|
console.error("[App] Failed to update tray menu", error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
if (!active) {
|
||||||
|
off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsubscribe = off;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(
|
console.error(
|
||||||
"[App] Failed to subscribe universal-provider-synced event",
|
"[App] Failed to subscribe universal-provider-synced event",
|
||||||
@@ -376,8 +389,9 @@ function App() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
setupListener();
|
void setupListener();
|
||||||
return () => {
|
return () => {
|
||||||
|
active = false;
|
||||||
unsubscribe?.();
|
unsubscribe?.();
|
||||||
};
|
};
|
||||||
}, [queryClient]);
|
}, [queryClient]);
|
||||||
@@ -429,9 +443,10 @@ function App() {
|
|||||||
// Listen for proxy-official-warning: warn when takeover is enabled with an official provider
|
// Listen for proxy-official-warning: warn when takeover is enabled with an official provider
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let unsubscribe: (() => void) | undefined;
|
let unsubscribe: (() => void) | undefined;
|
||||||
|
let active = true;
|
||||||
|
|
||||||
const setup = async () => {
|
const setup = async () => {
|
||||||
unsubscribe = await listen("proxy-official-warning", (event) => {
|
const off = await listen("proxy-official-warning", (event) => {
|
||||||
const { providerName } = event.payload as {
|
const { providerName } = event.payload as {
|
||||||
appType: string;
|
appType: string;
|
||||||
providerName: string;
|
providerName: string;
|
||||||
@@ -444,10 +459,16 @@ function App() {
|
|||||||
{ duration: 8000 },
|
{ duration: 8000 },
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
if (!active) {
|
||||||
|
off();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsubscribe = off;
|
||||||
};
|
};
|
||||||
|
|
||||||
void setup();
|
void setup();
|
||||||
return () => {
|
return () => {
|
||||||
|
active = false;
|
||||||
unsubscribe?.();
|
unsubscribe?.();
|
||||||
};
|
};
|
||||||
}, [t]);
|
}, [t]);
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import {
|
|||||||
} from "./useDirectorySettings";
|
} from "./useDirectorySettings";
|
||||||
import { useSettingsMetadata } from "./useSettingsMetadata";
|
import { useSettingsMetadata } from "./useSettingsMetadata";
|
||||||
|
|
||||||
type Language = "zh" | "en" | "ja";
|
|
||||||
|
|
||||||
interface SaveResult {
|
interface SaveResult {
|
||||||
requiresRestart: boolean;
|
requiresRestart: boolean;
|
||||||
}
|
}
|
||||||
@@ -402,11 +400,8 @@ export function useSettings(): UseSettingsResult {
|
|||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (typeof window !== "undefined") {
|
if (typeof window !== "undefined" && payload.language) {
|
||||||
window.localStorage.setItem(
|
window.localStorage.setItem("language", payload.language);
|
||||||
"language",
|
|
||||||
payload.language as Language,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(
|
console.warn(
|
||||||
|
|||||||
Reference in New Issue
Block a user