From bd23584fd72c51cfae5526eada4cf28dcdba3c0e Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sat, 30 May 2026 02:33:24 -0700 Subject: [PATCH] perf: reuse mounted ref in settings async panes --- .../components/settings/RepositoryIconPicker.tsx | 12 +++--------- src/renderer/src/components/settings/SshPane.tsx | 14 ++++---------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/src/renderer/src/components/settings/RepositoryIconPicker.tsx b/src/renderer/src/components/settings/RepositoryIconPicker.tsx index 2b993ff6e05..31f059296b8 100644 --- a/src/renderer/src/components/settings/RepositoryIconPicker.tsx +++ b/src/renderer/src/components/settings/RepositoryIconPicker.tsx @@ -1,4 +1,4 @@ -import { useEffect, useMemo, useRef, useState } from 'react' +import { useMemo, useState } from 'react' import { toast } from 'sonner' import { Github, Image, Link2, RotateCcw } from 'lucide-react' import type { Repo } from '../../../../shared/types' @@ -15,6 +15,7 @@ import { RepoIconGlyph, REPO_LUCIDE_ICON_OPTIONS } from '../repo/repo-icon' import { cn } from '@/lib/utils' import { useAppStore } from '@/store' import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client' +import { useMountedRef } from '@/hooks/useMountedRef' const EMOJI_OPTIONS = ['🚀', '✨', '💻', '🧠', '📦', '🔧', '🎨', '🌐', '📊', '🔒', '⚡', '✅'] @@ -27,7 +28,7 @@ export function RepositoryIconPicker({ }): React.JSX.Element { const [website, setWebsite] = useState('') const [loadingGitHub, setLoadingGitHub] = useState(false) - const mountedRef = useRef(true) + const mountedRef = useMountedRef() const activeRuntimeEnvironmentId = useAppStore( (state) => state.settings?.activeRuntimeEnvironmentId ?? null ) @@ -59,13 +60,6 @@ export function RepositoryIconPicker({ const setIcon = (repoIcon: RepoIcon | null) => updateRepo(repo.id, { repoIcon }) const setBadgeColor = (badgeColor: string) => updateRepo(repo.id, { badgeColor }) - useEffect(() => { - mountedRef.current = true - return () => { - mountedRef.current = false - } - }, []) - const handleUploadImage = async () => { try { const result = await window.api.shell.pickRepoIconImage() diff --git a/src/renderer/src/components/settings/SshPane.tsx b/src/renderer/src/components/settings/SshPane.tsx index 58b0e8c9692..fcd3724815d 100644 --- a/src/renderer/src/components/settings/SshPane.tsx +++ b/src/renderer/src/components/settings/SshPane.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useState } from 'react' import { toast } from 'sonner' import { Plus, Upload } from 'lucide-react' import { @@ -9,6 +9,7 @@ import { } from '../../../../shared/ssh-types' import { SSH_TERMINATE_RECONNECT_REQUIRED } from '../../../../shared/constants' import { useAppStore } from '@/store' +import { useMountedRef } from '@/hooks/useMountedRef' import { Button } from '../ui/button' import { removeSshTargetWithBestEffortCleanup } from './ssh-target-remove' import { SshTargetCard } from './SshTargetCard' @@ -29,7 +30,7 @@ export function SshPane(_props: SshPaneProps): React.JSX.Element { const [editingId, setEditingId] = useState(null) const [form, setForm] = useState(EMPTY_FORM) const [testingIds, setTestingIds] = useState>(new Set()) - const mountedRef = useRef(true) + const mountedRef = useMountedRef() const setSshTargetsMetadata = useAppStore((s) => s.setSshTargetsMetadata) const clearRemovedSshTargetState = useAppStore((s) => s.clearRemovedSshTargetState) @@ -49,16 +50,9 @@ export function SshPane(_props: SshPaneProps): React.JSX.Element { } } }, - [setSshTargetsMetadata] + [mountedRef, setSshTargetsMetadata] ) - useEffect(() => { - mountedRef.current = true - return () => { - mountedRef.current = false - } - }, []) - useEffect(() => { const abortController = new AbortController() void loadTargets({ signal: abortController.signal })