fix: 修复接口重复调用 — StrictMode 清理 + useModelList 去重

AppProvider useEffect 增加 aborted 标志,防止 React StrictMode
挂载→卸载→重新挂载时 refreshToken/getUserInfo 各调两次。

useModelList 提升到 LeftPanel 单例调用,通过 props 分发给
ModelSelector 和 TaskHistory,消除 /api/v1/models 重复请求。

DevTools 中显示「已停止」的请求即 StrictMode 第一轮挂载被丢弃的请求。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-09 19:24:34 +08:00
parent d95d155ab5
commit 848fdeca3d
7 changed files with 58 additions and 11 deletions

View File

@@ -107,10 +107,17 @@ export function AppProvider({ children }: AppProviderProps) {
}, []);
// ---------- 启动时初始化 token 存储 + 自动登录 ----------
//
// 注意React StrictMode开发模式会挂载→卸载→重新挂载以暴露副作用问题。
// aborted 标志确保卸载后不再执行异步回调,避免 refreshToken / getUserInfo 重复请求。
useEffect(() => {
let aborted = false;
// 从加密存储恢复 token 到内存缓存
Promise.all([initTokenStore(), initRefreshTokenStore()]).then(() => {
if (aborted) return;
// 初始化 401 刷新回调token 缓存就绪后才注册)
initAuthRefresh();
@@ -122,12 +129,14 @@ export function AppProvider({ children }: AppProviderProps) {
AuthAPI.refreshToken({ refresh_token: refreshToken })
.then(async (res) => {
if (aborted) return;
await setToken(res.access_token);
await setStoredRefreshToken(res.refresh_token);
setIsLoggedIn(true);
logger.info('auth', 'Auto-login succeeded');
// 补全用户信息
AuthAPI.getUserInfo().then((info) => {
if (aborted) return;
const u: LoginResponseBody = {
access_token: res.access_token,
refresh_token: res.refresh_token,
@@ -152,12 +161,15 @@ export function AppProvider({ children }: AppProviderProps) {
});
})
.catch(() => {
if (aborted) return;
logger.warn('auth', 'Auto-login failed, refresh_token expired');
clearStoredRefreshToken();
// 仅清除自动登录标记,保留用户名供下次表单回填
clearAutoLoginFlag();
});
});
return () => { aborted = true; };
}, []);
// ---------- 监听主进程推送的平台/版本信息 ----------