fix: refactor: 简化 Redux 数据管理逻辑并修复 bug
修复 clearCache/clearSpecificCache 引用不存在的 state.dynamicNews bug 简化数据插入逻辑,移除复杂的 Append/Replace/Jump 模式(虚拟滚动接管) 添加空数据边界处理和 toast 提示 添加 mode 参数支持(vertical/four-row) 修复默认值解构避免 undefined 错误 修复 Redux slice 未使用参数的 TS 警告 仅 preloadData 和 toggleEventFollow.rejected 的参数修改 将未使用的 state 参数改为 _state 前缀,消除 TS6133 警告
This commit is contained in:
@@ -157,9 +157,10 @@ export const fetchHotEvents = createAsyncThunk(
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取动态新闻(客户端缓存 + 智能请求)
|
* 获取动态新闻(客户端缓存 + 虚拟滚动)
|
||||||
* 用于 DynamicNewsCard 组件
|
* 用于 DynamicNewsCard 组件
|
||||||
* @param {Object} params - 请求参数
|
* @param {Object} params - 请求参数
|
||||||
|
* @param {string} params.mode - 显示模式('vertical' | 'four-row')
|
||||||
* @param {number} params.page - 页码
|
* @param {number} params.page - 页码
|
||||||
* @param {number} params.per_page - 每页数量
|
* @param {number} params.per_page - 每页数量
|
||||||
* @param {boolean} params.clearCache - 是否清空缓存(默认 false)
|
* @param {boolean} params.clearCache - 是否清空缓存(默认 false)
|
||||||
@@ -173,9 +174,10 @@ export const fetchHotEvents = createAsyncThunk(
|
|||||||
export const fetchDynamicNews = createAsyncThunk(
|
export const fetchDynamicNews = createAsyncThunk(
|
||||||
'communityData/fetchDynamicNews',
|
'communityData/fetchDynamicNews',
|
||||||
async ({
|
async ({
|
||||||
|
mode = 'vertical',
|
||||||
page = 1,
|
page = 1,
|
||||||
per_page = 5,
|
per_page = 5,
|
||||||
pageSize = 5, // 每页实际显示的数据量(用于计算索引)
|
pageSize = 5, // 🔍 添加 pageSize 参数(之前漏掉了)
|
||||||
clearCache = false,
|
clearCache = false,
|
||||||
prependMode = false,
|
prependMode = false,
|
||||||
sort = 'new',
|
sort = 'new',
|
||||||
@@ -214,11 +216,12 @@ export const fetchDynamicNews = createAsyncThunk(
|
|||||||
total: response.data.pagination?.total || 0
|
total: response.data.pagination?.total || 0
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
|
mode,
|
||||||
events: response.data.events,
|
events: response.data.events,
|
||||||
total: response.data.pagination?.total || 0,
|
total: response.data.pagination?.total || 0,
|
||||||
page,
|
page,
|
||||||
per_page,
|
per_page,
|
||||||
pageSize, // 返回 pageSize 用于索引计算
|
pageSize, // 🔍 添加 pageSize 到返回值
|
||||||
clearCache,
|
clearCache,
|
||||||
prependMode
|
prependMode
|
||||||
};
|
};
|
||||||
@@ -226,13 +229,15 @@ export const fetchDynamicNews = createAsyncThunk(
|
|||||||
|
|
||||||
logger.warn('CommunityData', '动态新闻返回数据为空', response);
|
logger.warn('CommunityData', '动态新闻返回数据为空', response);
|
||||||
return {
|
return {
|
||||||
|
mode,
|
||||||
events: [],
|
events: [],
|
||||||
total: 0,
|
total: 0,
|
||||||
page,
|
page,
|
||||||
per_page,
|
per_page,
|
||||||
pageSize, // 返回 pageSize 用于索引计算
|
pageSize, // 🔍 添加 pageSize 到返回值
|
||||||
clearCache,
|
clearCache,
|
||||||
prependMode
|
prependMode,
|
||||||
|
isEmpty: true // 标记为空数据,用于边界条件处理
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('CommunityData', '获取动态新闻失败', error);
|
logger.error('CommunityData', '获取动态新闻失败', error);
|
||||||
@@ -294,36 +299,48 @@ const communityDataSlice = createSlice({
|
|||||||
// 数据
|
// 数据
|
||||||
popularKeywords: [],
|
popularKeywords: [],
|
||||||
hotEvents: [],
|
hotEvents: [],
|
||||||
dynamicNews: [], // 动态新闻完整缓存列表
|
|
||||||
dynamicNewsTotal: 0, // 服务端总数量
|
// 纵向模式数据(独立存储)
|
||||||
|
verticalEvents: [], // 纵向模式完整缓存列表
|
||||||
|
verticalTotal: 0, // 纵向模式服务端总数量
|
||||||
|
verticalCachedCount: 0, // 纵向模式已缓存数量
|
||||||
|
|
||||||
|
// 平铺模式数据(独立存储)
|
||||||
|
fourRowEvents: [], // 平铺模式完整缓存列表
|
||||||
|
fourRowTotal: 0, // 平铺模式服务端总数量
|
||||||
|
fourRowCachedCount: 0, // 平铺模式已缓存数量
|
||||||
|
|
||||||
eventFollowStatus: {}, // 事件关注状态 { [eventId]: { isFollowing: boolean, followerCount: number } }
|
eventFollowStatus: {}, // 事件关注状态 { [eventId]: { isFollowing: boolean, followerCount: number } }
|
||||||
|
|
||||||
// 加载状态
|
// 加载状态
|
||||||
loading: {
|
loading: {
|
||||||
popularKeywords: false,
|
popularKeywords: false,
|
||||||
hotEvents: false,
|
hotEvents: false,
|
||||||
dynamicNews: false
|
verticalEvents: false,
|
||||||
|
fourRowEvents: false
|
||||||
},
|
},
|
||||||
|
|
||||||
// 错误信息
|
// 错误信息
|
||||||
error: {
|
error: {
|
||||||
popularKeywords: null,
|
popularKeywords: null,
|
||||||
hotEvents: null,
|
hotEvents: null,
|
||||||
dynamicNews: null
|
verticalEvents: null,
|
||||||
|
fourRowEvents: null
|
||||||
},
|
},
|
||||||
|
|
||||||
// 最后更新时间
|
// 最后更新时间
|
||||||
lastUpdated: {
|
lastUpdated: {
|
||||||
popularKeywords: null,
|
popularKeywords: null,
|
||||||
hotEvents: null,
|
hotEvents: null,
|
||||||
dynamicNews: null
|
verticalEvents: null,
|
||||||
|
fourRowEvents: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reducers: {
|
reducers: {
|
||||||
/**
|
/**
|
||||||
* 清除所有缓存(Redux + localStorage)
|
* 清除所有缓存(Redux + localStorage)
|
||||||
* 注意:dynamicNews 不使用 localStorage 缓存
|
* 注意:verticalEvents 和 fourRowEvents 不使用 localStorage 缓存
|
||||||
*/
|
*/
|
||||||
clearCache: (state) => {
|
clearCache: (state) => {
|
||||||
// 清除 localStorage
|
// 清除 localStorage
|
||||||
@@ -332,17 +349,27 @@ const communityDataSlice = createSlice({
|
|||||||
// 清除 Redux 状态
|
// 清除 Redux 状态
|
||||||
state.popularKeywords = [];
|
state.popularKeywords = [];
|
||||||
state.hotEvents = [];
|
state.hotEvents = [];
|
||||||
state.dynamicNews = []; // 动态新闻也清除
|
|
||||||
|
// 清除动态新闻数据(两个模式)
|
||||||
|
state.verticalEvents = [];
|
||||||
|
state.fourRowEvents = [];
|
||||||
|
state.verticalTotal = 0;
|
||||||
|
state.fourRowTotal = 0;
|
||||||
|
state.verticalCachedCount = 0;
|
||||||
|
state.fourRowCachedCount = 0;
|
||||||
|
|
||||||
|
// 清除更新时间
|
||||||
state.lastUpdated.popularKeywords = null;
|
state.lastUpdated.popularKeywords = null;
|
||||||
state.lastUpdated.hotEvents = null;
|
state.lastUpdated.hotEvents = null;
|
||||||
state.lastUpdated.dynamicNews = null;
|
state.lastUpdated.verticalEvents = null;
|
||||||
|
state.lastUpdated.fourRowEvents = null;
|
||||||
|
|
||||||
logger.info('CommunityData', '所有缓存已清除');
|
logger.info('CommunityData', '所有缓存已清除');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 清除指定类型的缓存
|
* 清除指定类型的缓存
|
||||||
* @param {string} payload - 缓存类型 ('popularKeywords' | 'hotEvents' | 'dynamicNews')
|
* @param {string} payload - 缓存类型 ('popularKeywords' | 'hotEvents' | 'verticalEvents' | 'fourRowEvents')
|
||||||
*/
|
*/
|
||||||
clearSpecificCache: (state, action) => {
|
clearSpecificCache: (state, action) => {
|
||||||
const type = action.payload;
|
const type = action.payload;
|
||||||
@@ -357,11 +384,20 @@ const communityDataSlice = createSlice({
|
|||||||
state.hotEvents = [];
|
state.hotEvents = [];
|
||||||
state.lastUpdated.hotEvents = null;
|
state.lastUpdated.hotEvents = null;
|
||||||
logger.info('CommunityData', '热点事件缓存已清除');
|
logger.info('CommunityData', '热点事件缓存已清除');
|
||||||
} else if (type === 'dynamicNews') {
|
} else if (type === 'verticalEvents') {
|
||||||
// dynamicNews 不使用 localStorage,只清除 Redux state
|
// verticalEvents 不使用 localStorage,只清除 Redux state
|
||||||
state.dynamicNews = [];
|
state.verticalEvents = [];
|
||||||
state.lastUpdated.dynamicNews = null;
|
state.verticalTotal = 0;
|
||||||
logger.info('CommunityData', '动态新闻数据已清除');
|
state.verticalCachedCount = 0;
|
||||||
|
state.lastUpdated.verticalEvents = null;
|
||||||
|
logger.info('CommunityData', '纵向模式事件数据已清除');
|
||||||
|
} else if (type === 'fourRowEvents') {
|
||||||
|
// fourRowEvents 不使用 localStorage,只清除 Redux state
|
||||||
|
state.fourRowEvents = [];
|
||||||
|
state.fourRowTotal = 0;
|
||||||
|
state.fourRowCachedCount = 0;
|
||||||
|
state.lastUpdated.fourRowEvents = null;
|
||||||
|
logger.info('CommunityData', '平铺模式事件数据已清除');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -369,7 +405,7 @@ const communityDataSlice = createSlice({
|
|||||||
* 预加载数据(用于应用启动时)
|
* 预加载数据(用于应用启动时)
|
||||||
* 注意:这不是异步 action,只是触发标记
|
* 注意:这不是异步 action,只是触发标记
|
||||||
*/
|
*/
|
||||||
preloadData: (state) => {
|
preloadData: (_state) => {
|
||||||
logger.info('CommunityData', '准备预加载数据');
|
logger.info('CommunityData', '准备预加载数据');
|
||||||
// 实际的预加载逻辑在组件中调用 dispatch(fetchPopularKeywords()) 等
|
// 实际的预加载逻辑在组件中调用 dispatch(fetchPopularKeywords()) 等
|
||||||
},
|
},
|
||||||
@@ -391,101 +427,90 @@ const communityDataSlice = createSlice({
|
|||||||
createDataReducers(builder, fetchHotEvents, 'hotEvents');
|
createDataReducers(builder, fetchHotEvents, 'hotEvents');
|
||||||
|
|
||||||
// dynamicNews 需要特殊处理(缓存 + 追加模式)
|
// dynamicNews 需要特殊处理(缓存 + 追加模式)
|
||||||
|
// 根据 mode 更新不同的 state(verticalEvents 或 fourRowEvents)
|
||||||
builder
|
builder
|
||||||
.addCase(fetchDynamicNews.pending, (state) => {
|
.addCase(fetchDynamicNews.pending, (state, action) => {
|
||||||
state.loading.dynamicNews = true;
|
const mode = action.meta.arg.mode || 'vertical';
|
||||||
state.error.dynamicNews = null;
|
const stateKey = mode === 'four-row' ? 'fourRowEvents' : 'verticalEvents';
|
||||||
|
state.loading[stateKey] = true;
|
||||||
|
state.error[stateKey] = null;
|
||||||
})
|
})
|
||||||
.addCase(fetchDynamicNews.fulfilled, (state, action) => {
|
.addCase(fetchDynamicNews.fulfilled, (state, action) => {
|
||||||
const { events, total, page, per_page, pageSize, clearCache, prependMode } = action.payload;
|
const { mode, events, total, page, clearCache, prependMode, isEmpty } = action.payload;
|
||||||
|
const stateKey = mode === 'four-row' ? 'fourRowEvents' : 'verticalEvents';
|
||||||
|
const totalKey = mode === 'four-row' ? 'fourRowTotal' : 'verticalTotal';
|
||||||
|
const cachedCountKey = mode === 'four-row' ? 'fourRowCachedCount' : 'verticalCachedCount';
|
||||||
|
|
||||||
|
// 边界条件:空数据只记录日志,不更新 state(保留现有数据)
|
||||||
|
if (isEmpty || (events.length === 0 && !clearCache)) {
|
||||||
|
logger.info('CommunityData', `${mode} 模式返回空数据,跳过更新`);
|
||||||
|
state.loading[stateKey] = false;
|
||||||
|
state.error[stateKey] = '暂无更多数据'; // 设置提示信息供组件显示 toast
|
||||||
|
return; // 提前返回,不更新数据
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔍 调试:收到数据
|
||||||
|
console.log('%c[Redux] fetchDynamicNews.fulfilled 收到数据', 'color: #10B981; font-weight: bold;', {
|
||||||
|
mode,
|
||||||
|
stateKey,
|
||||||
|
eventsCount: events.length,
|
||||||
|
total,
|
||||||
|
page,
|
||||||
|
clearCache,
|
||||||
|
prependMode,
|
||||||
|
'state[stateKey] 之前': state[stateKey].length,
|
||||||
|
});
|
||||||
|
|
||||||
if (clearCache) {
|
if (clearCache) {
|
||||||
// 清空缓存模式:直接替换
|
// 清空缓存模式:直接替换
|
||||||
state.dynamicNews = events;
|
state[stateKey] = events;
|
||||||
logger.debug('CommunityData', '清空缓存并加载新数据', {
|
logger.debug('CommunityData', `清空缓存并加载新数据 (${mode})`, {
|
||||||
count: events.length
|
count: events.length
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 🔍 调试:清空缓存后的状态
|
||||||
|
console.log('%c[Redux] clearCache 模式,直接替换数据', 'color: #10B981; font-weight: bold;', {
|
||||||
|
'state[stateKey] 之后': state[stateKey].length
|
||||||
|
});
|
||||||
} else if (prependMode) {
|
} else if (prependMode) {
|
||||||
// 追加到头部模式(用于定时刷新):去重后插入头部
|
// 追加到头部模式(用于定时刷新):去重后插入头部
|
||||||
const existingIds = new Set(state.dynamicNews.map(e => e.id));
|
const existingIds = new Set(state[stateKey].map(e => e.id));
|
||||||
const newEvents = events.filter(e => !existingIds.has(e.id));
|
const newEvents = events.filter(e => !existingIds.has(e.id));
|
||||||
state.dynamicNews = [...newEvents, ...state.dynamicNews];
|
state[stateKey] = [...newEvents, ...state[stateKey]];
|
||||||
logger.debug('CommunityData', '追加新数据到头部', {
|
logger.debug('CommunityData', `追加新数据到头部 (${mode})`, {
|
||||||
newCount: newEvents.length,
|
newCount: newEvents.length,
|
||||||
totalCount: state.dynamicNews.length
|
totalCount: state[stateKey].length
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 智能插入模式:根据页码计算正确的插入位置
|
// 简单追加模式:去重后追加到末尾(虚拟滚动组件处理展示逻辑)
|
||||||
// 使用 pageSize(每页显示量)而不是 per_page(请求数量)
|
const existingIds = new Set(state[stateKey].map(e => e.id));
|
||||||
const startIndex = (page - 1) * (pageSize || per_page);
|
|
||||||
|
|
||||||
// 判断插入模式
|
|
||||||
const isAppend = startIndex === state.dynamicNews.length;
|
|
||||||
const isReplace = startIndex < state.dynamicNews.length;
|
|
||||||
const isJump = startIndex > state.dynamicNews.length;
|
|
||||||
|
|
||||||
// 只在 append 模式下去重(避免定时刷新重复)
|
|
||||||
// 替换和跳页模式直接使用原始数据(避免因去重导致数据丢失)
|
|
||||||
if (isAppend) {
|
|
||||||
// Append 模式:连续加载,需要去重
|
|
||||||
const existingIds = new Set(
|
|
||||||
state.dynamicNews
|
|
||||||
.filter(e => e !== null)
|
|
||||||
.map(e => e.id)
|
|
||||||
);
|
|
||||||
const newEvents = events.filter(e => !existingIds.has(e.id));
|
const newEvents = events.filter(e => !existingIds.has(e.id));
|
||||||
state.dynamicNews = [...state.dynamicNews, ...newEvents];
|
state[stateKey] = [...state[stateKey], ...newEvents];
|
||||||
|
|
||||||
logger.debug('CommunityData', '连续追加数据(去重)', {
|
logger.debug('CommunityData', `追加新数据(去重,${mode})`, {
|
||||||
page,
|
page,
|
||||||
startIndex,
|
|
||||||
endIndex: startIndex + newEvents.length,
|
|
||||||
originalEventsCount: events.length,
|
originalEventsCount: events.length,
|
||||||
newEventsCount: newEvents.length,
|
newEventsCount: newEvents.length,
|
||||||
filteredCount: events.length - newEvents.length,
|
filteredCount: events.length - newEvents.length,
|
||||||
totalCount: state.dynamicNews.length
|
totalCount: state[stateKey].length
|
||||||
});
|
|
||||||
} else if (isReplace) {
|
|
||||||
// 替换模式:直接覆盖,不去重
|
|
||||||
const endIndex = startIndex + events.length;
|
|
||||||
const before = state.dynamicNews.slice(0, startIndex);
|
|
||||||
const after = state.dynamicNews.slice(endIndex);
|
|
||||||
state.dynamicNews = [...before, ...events, ...after];
|
|
||||||
|
|
||||||
logger.debug('CommunityData', '替换重叠数据(不去重)', {
|
|
||||||
page,
|
|
||||||
startIndex,
|
|
||||||
endIndex,
|
|
||||||
eventsCount: events.length,
|
|
||||||
beforeLength: before.length,
|
|
||||||
afterLength: after.length,
|
|
||||||
totalCount: state.dynamicNews.length
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 跳页模式:填充间隔,不去重
|
|
||||||
const gap = startIndex - state.dynamicNews.length;
|
|
||||||
const fillers = Array(gap).fill(null);
|
|
||||||
state.dynamicNews = [...state.dynamicNews, ...fillers, ...events];
|
|
||||||
|
|
||||||
logger.debug('CommunityData', '跳页加载,填充间隔(不去重)', {
|
|
||||||
page,
|
|
||||||
startIndex,
|
|
||||||
endIndex: startIndex + events.length,
|
|
||||||
gap,
|
|
||||||
eventsCount: events.length,
|
|
||||||
totalCount: state.dynamicNews.length
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
state.dynamicNewsTotal = total;
|
state[totalKey] = total;
|
||||||
state.loading.dynamicNews = false;
|
state[cachedCountKey] = state[stateKey].length; // 简化:不再有 null 占位符
|
||||||
state.lastUpdated.dynamicNews = new Date().toISOString();
|
|
||||||
|
[`state.${stateKey}.length`]: state[stateKey].length
|
||||||
|
});
|
||||||
|
|
||||||
|
state.loading[stateKey] = false;
|
||||||
|
state.lastUpdated[stateKey] = new Date().toISOString();
|
||||||
})
|
})
|
||||||
.addCase(fetchDynamicNews.rejected, (state, action) => {
|
.addCase(fetchDynamicNews.rejected, (state, action) => {
|
||||||
state.loading.dynamicNews = false;
|
const mode = action.meta.arg.mode || 'vertical';
|
||||||
state.error.dynamicNews = action.payload;
|
const stateKey = mode === 'four-row' ? 'fourRowEvents' : 'verticalEvents';
|
||||||
logger.error('CommunityData', 'dynamicNews 加载失败', new Error(action.payload));
|
state.loading[stateKey] = false;
|
||||||
|
state.error[stateKey] = action.payload;
|
||||||
|
logger.error('CommunityData', `${stateKey} 加载失败`, new Error(action.payload));
|
||||||
})
|
})
|
||||||
// toggleEventFollow
|
// toggleEventFollow
|
||||||
.addCase(toggleEventFollow.fulfilled, (state, action) => {
|
.addCase(toggleEventFollow.fulfilled, (state, action) => {
|
||||||
@@ -493,7 +518,7 @@ const communityDataSlice = createSlice({
|
|||||||
state.eventFollowStatus[eventId] = { isFollowing, followerCount };
|
state.eventFollowStatus[eventId] = { isFollowing, followerCount };
|
||||||
logger.debug('CommunityData', 'toggleEventFollow fulfilled', { eventId, isFollowing, followerCount });
|
logger.debug('CommunityData', 'toggleEventFollow fulfilled', { eventId, isFollowing, followerCount });
|
||||||
})
|
})
|
||||||
.addCase(toggleEventFollow.rejected, (state, action) => {
|
.addCase(toggleEventFollow.rejected, (_state, action) => {
|
||||||
logger.error('CommunityData', 'toggleEventFollow rejected', action.payload);
|
logger.error('CommunityData', 'toggleEventFollow rejected', action.payload);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -506,12 +531,21 @@ export const { clearCache, clearSpecificCache, preloadData, setEventFollowStatus
|
|||||||
// 基础选择器(Selectors)
|
// 基础选择器(Selectors)
|
||||||
export const selectPopularKeywords = (state) => state.communityData.popularKeywords;
|
export const selectPopularKeywords = (state) => state.communityData.popularKeywords;
|
||||||
export const selectHotEvents = (state) => state.communityData.hotEvents;
|
export const selectHotEvents = (state) => state.communityData.hotEvents;
|
||||||
export const selectDynamicNews = (state) => state.communityData.dynamicNews;
|
|
||||||
export const selectEventFollowStatus = (state) => state.communityData.eventFollowStatus;
|
export const selectEventFollowStatus = (state) => state.communityData.eventFollowStatus;
|
||||||
export const selectLoading = (state) => state.communityData.loading;
|
export const selectLoading = (state) => state.communityData.loading;
|
||||||
export const selectError = (state) => state.communityData.error;
|
export const selectError = (state) => state.communityData.error;
|
||||||
export const selectLastUpdated = (state) => state.communityData.lastUpdated;
|
export const selectLastUpdated = (state) => state.communityData.lastUpdated;
|
||||||
|
|
||||||
|
// 纵向模式数据选择器
|
||||||
|
export const selectVerticalEvents = (state) => state.communityData.verticalEvents;
|
||||||
|
export const selectVerticalTotal = (state) => state.communityData.verticalTotal;
|
||||||
|
export const selectVerticalCachedCount = (state) => state.communityData.verticalCachedCount;
|
||||||
|
|
||||||
|
// 平铺模式数据选择器
|
||||||
|
export const selectFourRowEvents = (state) => state.communityData.fourRowEvents;
|
||||||
|
export const selectFourRowTotal = (state) => state.communityData.fourRowTotal;
|
||||||
|
export const selectFourRowCachedCount = (state) => state.communityData.fourRowCachedCount;
|
||||||
|
|
||||||
// 组合选择器
|
// 组合选择器
|
||||||
export const selectPopularKeywordsWithLoading = (state) => ({
|
export const selectPopularKeywordsWithLoading = (state) => ({
|
||||||
data: state.communityData.popularKeywords,
|
data: state.communityData.popularKeywords,
|
||||||
@@ -527,13 +561,24 @@ export const selectHotEventsWithLoading = (state) => ({
|
|||||||
lastUpdated: state.communityData.lastUpdated.hotEvents
|
lastUpdated: state.communityData.lastUpdated.hotEvents
|
||||||
});
|
});
|
||||||
|
|
||||||
export const selectDynamicNewsWithLoading = (state) => ({
|
// 纵向模式数据 + 加载状态选择器
|
||||||
data: state.communityData.dynamicNews, // 完整缓存列表(可能包含 null 占位符)
|
export const selectVerticalEventsWithLoading = (state) => ({
|
||||||
loading: state.communityData.loading.dynamicNews,
|
data: state.communityData.verticalEvents, // 完整缓存列表(可能包含 null 占位符)
|
||||||
error: state.communityData.error.dynamicNews,
|
loading: state.communityData.loading.verticalEvents,
|
||||||
total: state.communityData.dynamicNewsTotal, // 服务端总数量
|
error: state.communityData.error.verticalEvents,
|
||||||
cachedCount: state.communityData.dynamicNews.filter(e => e !== null).length, // 已缓存有效数量(排除 null)
|
total: state.communityData.verticalTotal, // 服务端总数量
|
||||||
lastUpdated: state.communityData.lastUpdated.dynamicNews
|
cachedCount: state.communityData.verticalCachedCount, // 已缓存有效数量(排除 null)
|
||||||
|
lastUpdated: state.communityData.lastUpdated.verticalEvents
|
||||||
|
});
|
||||||
|
|
||||||
|
// 平铺模式数据 + 加载状态选择器
|
||||||
|
export const selectFourRowEventsWithLoading = (state) => ({
|
||||||
|
data: state.communityData.fourRowEvents, // 完整缓存列表(可能包含 null 占位符)
|
||||||
|
loading: state.communityData.loading.fourRowEvents,
|
||||||
|
error: state.communityData.error.fourRowEvents,
|
||||||
|
total: state.communityData.fourRowTotal, // 服务端总数量
|
||||||
|
cachedCount: state.communityData.fourRowCachedCount, // 已缓存有效数量(排除 null)
|
||||||
|
lastUpdated: state.communityData.lastUpdated.fourRowEvents
|
||||||
});
|
});
|
||||||
|
|
||||||
// 工具函数:检查数据是否需要刷新(超过指定时间)
|
// 工具函数:检查数据是否需要刷新(超过指定时间)
|
||||||
|
|||||||
Reference in New Issue
Block a user