feat: improve error handling and manage component mount state in AiProvidersAmpcodeEditPage

This commit is contained in:
LTbinglingfeng
2026-01-30 02:00:35 +08:00
parent 5c85df486e
commit 129d89cf67
2 changed files with 28 additions and 29 deletions

View File

@@ -17,6 +17,12 @@ import type { AmpcodeFormState } from '@/components/providers';
type LocationState = { fromAiProviders?: boolean } | null; type LocationState = { fromAiProviders?: boolean } | null;
const getErrorMessage = (err: unknown) => {
if (err instanceof Error) return err.message;
if (typeof err === 'string') return err;
return '';
};
export function AiProvidersAmpcodeEditPage() { export function AiProvidersAmpcodeEditPage() {
const { t } = useTranslation(); const { t } = useTranslation();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -36,15 +42,10 @@ export function AiProvidersAmpcodeEditPage() {
const [error, setError] = useState(''); const [error, setError] = useState('');
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const initializedRef = useRef(false); const initializedRef = useRef(false);
const mountedRef = useRef(false);
const title = useMemo(() => t('ai_providers.ampcode_modal_title'), [t]); const title = useMemo(() => t('ai_providers.ampcode_modal_title'), [t]);
const getErrorMessage = (err: unknown) => {
if (err instanceof Error) return err.message;
if (typeof err === 'string') return err;
return '';
};
const handleBack = useCallback(() => { const handleBack = useCallback(() => {
const state = location.state as LocationState; const state = location.state as LocationState;
if (state?.fromAiProviders) { if (state?.fromAiProviders) {
@@ -66,6 +67,13 @@ export function AiProvidersAmpcodeEditPage() {
return () => window.removeEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown);
}, [handleBack]); }, [handleBack]);
useEffect(() => {
mountedRef.current = true;
return () => {
mountedRef.current = false;
};
}, []);
useEffect(() => { useEffect(() => {
if (initializedRef.current) return; if (initializedRef.current) return;
initializedRef.current = true; initializedRef.current = true;
@@ -74,31 +82,26 @@ export function AiProvidersAmpcodeEditPage() {
setLoaded(false); setLoaded(false);
setMappingsDirty(false); setMappingsDirty(false);
setError(''); setError('');
setForm(buildAmpcodeFormState(config?.ampcode ?? null)); setForm(buildAmpcodeFormState(useConfigStore.getState().config?.ampcode ?? null));
void (async () => {
try {
const ampcode = await ampcodeApi.getAmpcode();
if (!mountedRef.current) return;
let cancelled = false;
ampcodeApi
.getAmpcode()
.then((ampcode) => {
if (cancelled) return;
setLoaded(true); setLoaded(true);
updateConfigValue('ampcode', ampcode); updateConfigValue('ampcode', ampcode);
clearCache('ampcode'); clearCache('ampcode');
setForm(buildAmpcodeFormState(ampcode)); setForm(buildAmpcodeFormState(ampcode));
}) } catch (err: unknown) {
.catch((err: unknown) => { if (!mountedRef.current) return;
if (cancelled) return;
setError(getErrorMessage(err) || t('notification.refresh_failed')); setError(getErrorMessage(err) || t('notification.refresh_failed'));
}) } finally {
.finally(() => { if (!mountedRef.current) return;
if (cancelled) return;
setLoading(false); setLoading(false);
}); }
})();
return () => { }, [clearCache, t, updateConfigValue]);
cancelled = true;
};
}, [clearCache, config?.ampcode, t, updateConfigValue]);
const clearAmpcodeUpstreamApiKey = async () => { const clearAmpcodeUpstreamApiKey = async () => {
showConfirmation({ showConfirmation({

View File

@@ -1,4 +1,4 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useCallback, useEffect, useMemo, useState } from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom'; import { useLocation, useNavigate, useParams } from 'react-router-dom';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Card } from '@/components/ui/Card'; import { Card } from '@/components/ui/Card';
@@ -51,7 +51,6 @@ export function AiProvidersVertexEditPage() {
const [saving, setSaving] = useState(false); const [saving, setSaving] = useState(false);
const [error, setError] = useState(''); const [error, setError] = useState('');
const [form, setForm] = useState<VertexFormState>(() => buildEmptyForm()); const [form, setForm] = useState<VertexFormState>(() => buildEmptyForm());
const initializedRef = useRef(false);
const hasIndexParam = typeof params.index === 'string'; const hasIndexParam = typeof params.index === 'string';
const editIndex = useMemo(() => parseIndexParam(params.index), [params.index]); const editIndex = useMemo(() => parseIndexParam(params.index), [params.index]);
@@ -89,9 +88,6 @@ export function AiProvidersVertexEditPage() {
}, [handleBack]); }, [handleBack]);
useEffect(() => { useEffect(() => {
if (initializedRef.current) return;
initializedRef.current = true;
let cancelled = false; let cancelled = false;
setLoading(true); setLoading(true);
setError(''); setError('');