refactor: Enhance fetchIssues logic with mounted state checks

- Introduced a useRef hook to track component mount status, preventing state updates on unmounted components.
- Updated fetchIssues function to conditionally set state only if the component is still mounted, improving reliability during asynchronous operations.
- Ensured proper cleanup in useEffect to maintain accurate mounted state, enhancing overall component stability.
This commit is contained in:
Kacper
2025-12-24 02:31:56 +01:00
parent a85e1aaa89
commit 38addacf1e

View File

@@ -1,4 +1,4 @@
import { useState, useEffect, useCallback } from 'react'; import { useState, useEffect, useCallback, useRef } from 'react';
import { getElectronAPI, GitHubIssue } from '@/lib/electron'; import { getElectronAPI, GitHubIssue } from '@/lib/electron';
import { useAppStore } from '@/store/app-store'; import { useAppStore } from '@/store/app-store';
@@ -9,41 +9,59 @@ export function useGithubIssues() {
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const isMountedRef = useRef(true);
const fetchIssues = useCallback(async () => { const fetchIssues = useCallback(async () => {
if (!currentProject?.path) { if (!currentProject?.path) {
setError('No project selected'); if (isMountedRef.current) {
setLoading(false); setError('No project selected');
setLoading(false);
}
return; return;
} }
try { try {
setError(null); if (isMountedRef.current) {
setError(null);
}
const api = getElectronAPI(); const api = getElectronAPI();
if (api.github) { if (api.github) {
const result = await api.github.listIssues(currentProject.path); const result = await api.github.listIssues(currentProject.path);
if (result.success) { if (isMountedRef.current) {
setOpenIssues(result.openIssues || []); if (result.success) {
setClosedIssues(result.closedIssues || []); setOpenIssues(result.openIssues || []);
} else { setClosedIssues(result.closedIssues || []);
setError(result.error || 'Failed to fetch issues'); } else {
setError(result.error || 'Failed to fetch issues');
}
} }
} }
} catch (err) { } catch (err) {
console.error('[GitHubIssuesView] Error fetching issues:', err); if (isMountedRef.current) {
setError(err instanceof Error ? err.message : 'Failed to fetch issues'); console.error('[GitHubIssuesView] Error fetching issues:', err);
setError(err instanceof Error ? err.message : 'Failed to fetch issues');
}
} finally { } finally {
setLoading(false); if (isMountedRef.current) {
setRefreshing(false); setLoading(false);
setRefreshing(false);
}
} }
}, [currentProject?.path]); }, [currentProject?.path]);
useEffect(() => { useEffect(() => {
isMountedRef.current = true;
fetchIssues(); fetchIssues();
return () => {
isMountedRef.current = false;
};
}, [fetchIssues]); }, [fetchIssues]);
const refresh = useCallback(() => { const refresh = useCallback(() => {
setRefreshing(true); if (isMountedRef.current) {
setRefreshing(true);
}
fetchIssues(); fetchIssues();
}, [fetchIssues]); }, [fetchIssues]);