React+Redux+RTKQ Electron应用启动时如何通过持久化令牌获取用户数据?
实现方案
1. 在RTKQ中定义用户详情查询端点
先在你的baseApi中添加获取用户详情的查询端点,利用RTKQ的自动认证头处理逻辑:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; import { RootState } from '../store'; // 定义用户数据类型 interface User { id: string; name: string; email: string; // 补充你的用户字段 } export const baseApi = createApi({ reducerPath: 'baseApi', baseQuery: fetchBaseQuery({ baseUrl: '/your-api-base-url', prepareHeaders: (headers, { getState }) => { // 从已加载的Redux Auth状态中取令牌 const token = (getState() as RootState).auth.token; if (token) { headers.set('Authorization', `Bearer ${token}`); } return headers; }, }), endpoints: (builder) => ({ getUserDetails: builder.query<User, void>({ query: () => '/user/me', }), }), }); // 导出RTKQ自动生成的Hook export const { useGetUserDetailsQuery } = baseApi;
2. 在根组件中控制加载屏与UI流转
在应用入口组件(比如App.tsx)中,结合Redux状态和RTKQ的查询状态,实现启动屏的显示逻辑:
import { useSelector } from 'react-redux'; import { useGetUserDetailsQuery } from './api/baseApi'; import { RootState } from './store'; import LoadingSplash from './components/LoadingSplash'; import MainApp from './components/MainApp'; import LoginScreen from './components/LoginScreen'; function App() { const { token } = useSelector((state: RootState) => state.auth); // 仅当存在令牌时触发用户详情查询 const { data: user, isLoading, error } = useGetUserDetailsQuery(undefined, { skip: !token, // 无令牌时跳过无效请求 refetchOnMountOrArgChange: true, // 确保每次启动都拉取最新数据 }); // 有令牌且正在加载:显示启动屏 if (token && isLoading) { return <LoadingSplash />; } // 有令牌但查询失败(比如令牌过期):跳转登录页 if (token && error) { return <LoginScreen />; } // 获取到用户数据:显示主应用 if (user) { return <MainApp user={user} />; } // 无令牌:显示登录页 return <LoginScreen />; } export default App;
3. (可选)结合Electron原生启动屏优化体验
如果需要使用Electron原生启动屏而非纯React组件,可以通过IPC通信在用户数据加载完成后再显示主窗口:
主进程(main.ts):
import { app, BrowserWindow, ipcMain } from 'electron'; import path from 'path'; let mainWindow: BrowserWindow | null; function createWindow() { mainWindow = new BrowserWindow({ width: 800, height: 600, show: false, // 初始不显示主窗口 webPreferences: { preload: path.join(__dirname, 'preload.js'), contextIsolation: true, nodeIntegration: false, }, }); mainWindow.loadFile('index.html'); // 监听渲染进程的加载完成信号 ipcMain.on('user-data-ready', () => { mainWindow?.show(); // 显示主窗口 // 若使用了Electron原生启动屏模块,可在此关闭: // splashScreen.close(); }); mainWindow.on('closed', () => { mainWindow = null; }); } app.whenReady().then(createWindow);
渲染进程(App.tsx):
添加useEffect发送IPC信号通知主进程:
import { useEffect } from 'react'; import { ipcRenderer } from 'electron'; // ...其他导入 function App() { // ...之前的状态与查询逻辑 useEffect(() => { // 用户数据加载完成后通知主进程 if (user) { ipcRenderer.send('user-data-ready'); } }, [user]); // ...渲染逻辑 }
关键注意点
- 无效请求拦截:通过
skip: !token避免无令牌时发起无效API请求 - 异常处理:令牌存在但查询失败时,及时引导用户重新登录
- 缓存控制:
refetchOnMountOrArgChange: true确保每次启动都获取最新用户数据
内容的提问来源于stack exchange,提问作者Rychu
相关产品推荐
相关产品推荐

