fix(git): stop PR section refresh loop causing React #185 (#588)

Prevent a feedback loop between remote selection and refresh effects in PullRequestSection. This keeps refresh callback dependencies stable and avoids repeated state updates that triggered maximum update depth errors in desktop Git PR view.
This commit is contained in:
Iuliia Ivashko
2026-03-03 16:42:36 +02:00
committed by GitHub
parent 855412ce79
commit 0b6c1e4165
@@ -416,6 +416,7 @@ export const PullRequestSection: React.FC<{
const lastRefreshAtRef = React.useRef(0);
const lastDiscoveryPollAtRef = React.useRef(0);
const statusRef = React.useRef<GitHubPullRequestStatus | null>(null);
const selectedRemoteNameRef = React.useRef<string | null>(selectedRemote?.name ?? null);
const attemptedBodyHydrationRef = React.useRef<Set<string>>(new Set());
const lastSyncedPrNumberRef = React.useRef<number | null>(null);
@@ -926,6 +927,10 @@ export const PullRequestSection: React.FC<{
statusRef.current = status;
}, [status]);
React.useEffect(() => {
selectedRemoteNameRef.current = selectedRemote?.name ?? null;
}, [selectedRemote?.name]);
const refresh = React.useCallback(async (options?: { force?: boolean; onlyExistingPr?: boolean; silent?: boolean; markInitialResolved?: boolean }) => {
if (!canShow) return;
if (options?.onlyExistingPr && !statusRef.current?.pr) {
@@ -967,7 +972,7 @@ export const PullRequestSection: React.FC<{
}
setError(null);
try {
const next = await github.prStatus(directory, branch, selectedRemote?.name);
const next = await github.prStatus(directory, branch, selectedRemoteNameRef.current ?? undefined);
setStatus((prev) => {
const nextPr = next.pr;
const prevPr = prev?.pr;
@@ -1014,11 +1019,11 @@ export const PullRequestSection: React.FC<{
}
isRefreshInFlightRef.current = false;
}
}, [branch, canShow, directory, github, githubAuthChecked, githubAuthStatus, selectedRemote?.name]);
}, [branch, canShow, directory, github, githubAuthChecked, githubAuthStatus]);
// Refetch PR status when selected remote changes
const handleRemoteChange = React.useCallback((remote: GitRemote) => {
setSelectedRemote(remote);
setSelectedRemote((prev) => (prev?.name === remote.name ? prev : remote));
// Clear current status and refetch
setStatus(null);
setError(null);
@@ -1032,24 +1037,26 @@ export const PullRequestSection: React.FC<{
setBody(snapshot?.body ?? '');
setDraft(snapshot?.draft ?? false);
setTargetBaseBranch(snapshot?.targetBaseBranch ? normalizeBranchRef(snapshot.targetBaseBranch) : normalizeBranchRef(baseBranch));
setSelectedRemote(
pickInitialPrRemote(remotes, {
selectedRemoteName: snapshot?.selectedRemoteName,
trackingBranch,
})
);
const nextRemote = pickInitialPrRemote(remotes, {
selectedRemoteName: snapshot?.selectedRemoteName,
trackingBranch,
});
setSelectedRemote((prev) => (prev?.name === nextRemote?.name ? prev : nextRemote));
setStatus(statusSnapshot);
setError(null);
setIsInitialStatusResolved(Boolean(statusSnapshot));
}, [baseBranch, branch, remotes, snapshotKey, trackingBranch]);
React.useEffect(() => {
void refresh({ force: true, markInitialResolved: true });
}, [baseBranch, branch, refresh, remotes, snapshotKey, trackingBranch]);
}, [snapshotKey, refresh]);
// Refetch when selected remote changes
React.useEffect(() => {
if (selectedRemote) {
if (selectedRemote?.name) {
void refresh({ force: true, markInitialResolved: true });
}
}, [selectedRemote, refresh]);
}, [selectedRemote?.name, refresh]);
React.useEffect(() => {
const onFocus = () => {