mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +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(() => {
|
||||
let unsubscribe: (() => void) | undefined;
|
||||
let active = true;
|
||||
|
||||
const setupListener = async () => {
|
||||
try {
|
||||
unsubscribe = await providersApi.onSwitched(
|
||||
const off = await providersApi.onSwitched(
|
||||
async (event: ProviderSwitchEvent) => {
|
||||
if (event.appType === activeApp) {
|
||||
await refetch();
|
||||
}
|
||||
},
|
||||
);
|
||||
if (!active) {
|
||||
off();
|
||||
return;
|
||||
}
|
||||
unsubscribe = off;
|
||||
} catch (error) {
|
||||
console.error("[App] Failed to subscribe provider switch event", error);
|
||||
}
|
||||
};
|
||||
|
||||
setupListener();
|
||||
void setupListener();
|
||||
return () => {
|
||||
active = false;
|
||||
unsubscribe?.();
|
||||
};
|
||||
}, [activeApp, refetch]);
|
||||
|
||||
useEffect(() => {
|
||||
let unsubscribe: (() => void) | undefined;
|
||||
let active = true;
|
||||
|
||||
const setupListener = async () => {
|
||||
try {
|
||||
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"] });
|
||||
try {
|
||||
await providersApi.updateTrayMenu();
|
||||
@@ -368,6 +376,11 @@ function App() {
|
||||
console.error("[App] Failed to update tray menu", error);
|
||||
}
|
||||
});
|
||||
if (!active) {
|
||||
off();
|
||||
return;
|
||||
}
|
||||
unsubscribe = off;
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"[App] Failed to subscribe universal-provider-synced event",
|
||||
@@ -376,8 +389,9 @@ function App() {
|
||||
}
|
||||
};
|
||||
|
||||
setupListener();
|
||||
void setupListener();
|
||||
return () => {
|
||||
active = false;
|
||||
unsubscribe?.();
|
||||
};
|
||||
}, [queryClient]);
|
||||
@@ -429,9 +443,10 @@ function App() {
|
||||
// Listen for proxy-official-warning: warn when takeover is enabled with an official provider
|
||||
useEffect(() => {
|
||||
let unsubscribe: (() => void) | undefined;
|
||||
let active = true;
|
||||
|
||||
const setup = async () => {
|
||||
unsubscribe = await listen("proxy-official-warning", (event) => {
|
||||
const off = await listen("proxy-official-warning", (event) => {
|
||||
const { providerName } = event.payload as {
|
||||
appType: string;
|
||||
providerName: string;
|
||||
@@ -444,10 +459,16 @@ function App() {
|
||||
{ duration: 8000 },
|
||||
);
|
||||
});
|
||||
if (!active) {
|
||||
off();
|
||||
return;
|
||||
}
|
||||
unsubscribe = off;
|
||||
};
|
||||
|
||||
void setup();
|
||||
return () => {
|
||||
active = false;
|
||||
unsubscribe?.();
|
||||
};
|
||||
}, [t]);
|
||||
|
||||
@@ -14,8 +14,6 @@ import {
|
||||
} from "./useDirectorySettings";
|
||||
import { useSettingsMetadata } from "./useSettingsMetadata";
|
||||
|
||||
type Language = "zh" | "en" | "ja";
|
||||
|
||||
interface SaveResult {
|
||||
requiresRestart: boolean;
|
||||
}
|
||||
@@ -402,11 +400,8 @@ export function useSettings(): UseSettingsResult {
|
||||
);
|
||||
|
||||
try {
|
||||
if (typeof window !== "undefined") {
|
||||
window.localStorage.setItem(
|
||||
"language",
|
||||
payload.language as Language,
|
||||
);
|
||||
if (typeof window !== "undefined" && payload.language) {
|
||||
window.localStorage.setItem("language", payload.language);
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
|
||||
Reference in New Issue
Block a user