feat: 添加 RTK Query 集成用于事件数据获取(实验性)...
This commit is contained in:
144
src/store/api/eventsApi.js
Normal file
144
src/store/api/eventsApi.js
Normal file
@@ -0,0 +1,144 @@
|
||||
// src/store/api/eventsApi.js
|
||||
// RTK Query API for Events - 事件数据获取 API
|
||||
|
||||
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
|
||||
import { logger } from '../../utils/logger';
|
||||
|
||||
/**
|
||||
* Events API Slice - 使用 RTK Query 管理事件数据
|
||||
*
|
||||
* 特性:
|
||||
* - ✅ 自动缓存管理(按 queryKey 缓存)
|
||||
* - ✅ 自动去重请求
|
||||
* - ✅ 返回第一页刷新数据(invalidateTags)
|
||||
* - ✅ 预加载支持(prefetch)
|
||||
* - ✅ 统一在 Redux DevTools 中调试
|
||||
* - ✅ 无需额外 Provider
|
||||
*/
|
||||
export const eventsApi = createApi({
|
||||
reducerPath: 'eventsApi',
|
||||
|
||||
// 基础查询配置
|
||||
baseQuery: fetchBaseQuery({
|
||||
baseUrl: '/api',
|
||||
prepareHeaders: (headers) => {
|
||||
// 可以在这里添加认证 token
|
||||
// const token = localStorage.getItem('token');
|
||||
// if (token) {
|
||||
// headers.set('Authorization', `Bearer ${token}`);
|
||||
// }
|
||||
return headers;
|
||||
},
|
||||
}),
|
||||
|
||||
// 标签类型定义(用于缓存失效)
|
||||
tagTypes: ['Events'],
|
||||
|
||||
// API 端点定义
|
||||
endpoints: (builder) => ({
|
||||
/**
|
||||
* 获取分页事件列表
|
||||
*
|
||||
* @param {Object} params
|
||||
* @param {number} params.page - 页码
|
||||
* @param {number} params.per_page - 每页数量
|
||||
* @param {string} params.mode - 显示模式(vertical / four-row)
|
||||
* @param {string} params.sort - 排序方式
|
||||
* @param {string} params.importance - 重要性筛选
|
||||
* @param {string} params.q - 搜索关键词
|
||||
* @param {string} params.date_range - 日期范围
|
||||
* @param {string} params.industry_code - 行业代码
|
||||
*
|
||||
* @returns {Object} { events: Array, pagination: Object }
|
||||
*/
|
||||
getEvents: builder.query({
|
||||
query: ({ page = 1, per_page = 5, mode = 'vertical', ...filters }) => {
|
||||
logger.debug('eventsApi', 'getEvents 请求', {
|
||||
page,
|
||||
per_page,
|
||||
mode,
|
||||
filters,
|
||||
});
|
||||
|
||||
return {
|
||||
url: '/events',
|
||||
params: {
|
||||
page,
|
||||
per_page,
|
||||
...filters,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
// 🔥 缓存标签:用于缓存失效
|
||||
providesTags: (result, error, { page, mode }) => {
|
||||
if (error) return [];
|
||||
|
||||
return [
|
||||
{ type: 'Events', id: `${mode}-${page}` }, // 具体页面的标签
|
||||
{ type: 'Events', id: `${mode}-LIST` }, // 模式的总标签
|
||||
];
|
||||
},
|
||||
|
||||
// 转换响应数据
|
||||
transformResponse: (response) => {
|
||||
logger.debug('eventsApi', 'getEvents 响应', {
|
||||
eventsCount: response.data?.events?.length,
|
||||
total: response.data?.pagination?.total,
|
||||
});
|
||||
|
||||
if (!response.success || !response.data?.events) {
|
||||
throw new Error('数据格式错误');
|
||||
}
|
||||
|
||||
return {
|
||||
events: response.data.events,
|
||||
pagination: response.data.pagination || {},
|
||||
};
|
||||
},
|
||||
|
||||
// 错误处理
|
||||
transformErrorResponse: (response) => {
|
||||
logger.error('eventsApi', 'getEvents 失败', new Error(response.status));
|
||||
return {
|
||||
status: response.status,
|
||||
message: response.data?.message || '获取事件数据失败',
|
||||
};
|
||||
},
|
||||
|
||||
// 🔥 keepUnusedDataFor: 缓存保留时间(秒)
|
||||
keepUnusedDataFor: 600, // 10分钟
|
||||
|
||||
// 🔥 合并查询结果(用于无限滚动)
|
||||
// serializeQueryArgs: ({ endpointName, queryArgs }) => {
|
||||
// const { mode, ...filters } = queryArgs;
|
||||
// return `${endpointName}(${mode})`;
|
||||
// },
|
||||
// merge: (currentCache, newItems) => {
|
||||
// currentCache.events.push(...newItems.events);
|
||||
// },
|
||||
// forceRefetch: ({ currentArg, previousArg }) => {
|
||||
// return currentArg.page !== previousArg?.page;
|
||||
// },
|
||||
}),
|
||||
|
||||
/**
|
||||
* 预加载下一页(性能优化)
|
||||
*
|
||||
* 用法:
|
||||
* dispatch(eventsApi.util.prefetch('getEvents', { page: 2, ... }))
|
||||
*/
|
||||
}),
|
||||
});
|
||||
|
||||
// 导出自动生成的 Hooks
|
||||
export const {
|
||||
useGetEventsQuery,
|
||||
useLazyGetEventsQuery, // 手动触发的版本
|
||||
usePrefetch, // 预加载 Hook
|
||||
} = eventsApi;
|
||||
|
||||
// 导出工具方法
|
||||
export const {
|
||||
util: { invalidateTags, prefetch },
|
||||
} = eventsApi;
|
||||
@@ -7,6 +7,7 @@ import stockReducer from './slices/stockSlice';
|
||||
import authModalReducer from './slices/authModalSlice';
|
||||
import subscriptionReducer from './slices/subscriptionSlice';
|
||||
import posthogMiddleware from './middleware/posthogMiddleware';
|
||||
import { eventsApi } from './api/eventsApi'; // ✅ RTK Query API
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
@@ -16,6 +17,7 @@ export const store = configureStore({
|
||||
stock: stockReducer, // ✅ 股票和事件数据管理
|
||||
authModal: authModalReducer, // ✅ 认证弹窗状态管理
|
||||
subscription: subscriptionReducer, // ✅ 订阅信息状态管理
|
||||
[eventsApi.reducerPath]: eventsApi.reducer, // ✅ RTK Query 事件 API
|
||||
},
|
||||
middleware: (getDefaultMiddleware) =>
|
||||
getDefaultMiddleware({
|
||||
@@ -29,7 +31,9 @@ export const store = configureStore({
|
||||
'stock/fetchStockQuotes/fulfilled',
|
||||
],
|
||||
},
|
||||
}).concat(posthogMiddleware), // ✅ PostHog 自动追踪中间件
|
||||
})
|
||||
.concat(posthogMiddleware) // ✅ PostHog 自动追踪中间件
|
||||
.concat(eventsApi.middleware), // ✅ RTK Query 中间件(自动缓存、去重、重试)
|
||||
});
|
||||
|
||||
export default store;
|
||||
|
||||
Reference in New Issue
Block a user