feat:拆分 handlePageChange 为子函数(减少复杂度)

This commit is contained in:
zdl
2025-11-04 15:05:25 +08:00
parent 0a10270ab0
commit 67981f21a2

View File

@@ -57,30 +57,21 @@ const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast })
return allCachedEvents.slice(startIndex, endIndex).filter(event => event !== null); return allCachedEvents.slice(startIndex, endIndex).filter(event => event !== null);
}, [allCachedEvents, currentPage, pageSize]); }, [allCachedEvents, currentPage, pageSize]);
// 翻页处理(智能预加载) /**
const handlePageChange = useCallback(async (newPage) => { * 子函数1: 检查目标页缓存状态
// 🔍 诊断日志 - 记录翻页开始状态 * @param {number} targetPage - 目标页码
console.log('[handlePageChange] 开始翻页', { * @returns {Object} { isTargetPageCached, targetPageInfo }
currentPage, */
newPage, const checkTargetPageCache = useCallback((targetPage) => {
pageSize, const targetPageStartIndex = (targetPage - 1) * pageSize;
totalPages,
hasMore,
total,
allCachedEventsLength: allCachedEvents.length,
cachedCount
});
// 0. 首先检查目标页数据是否已完整缓存
const targetPageStartIndex = (newPage - 1) * pageSize;
const targetPageEndIndex = targetPageStartIndex + pageSize; const targetPageEndIndex = targetPageStartIndex + pageSize;
const targetPageData = allCachedEvents.slice(targetPageStartIndex, targetPageEndIndex); const targetPageData = allCachedEvents.slice(targetPageStartIndex, targetPageEndIndex);
const validTargetData = targetPageData.filter(e => e !== null); const validTargetData = targetPageData.filter(e => e !== null);
const expectedCount = Math.min(pageSize, total - targetPageStartIndex); const expectedCount = Math.min(pageSize, total - targetPageStartIndex);
const isTargetPageCached = validTargetData.length >= expectedCount; const isTargetPageCached = validTargetData.length >= expectedCount;
console.log('[handlePageChange] 目标页缓存检查', { console.log('[checkTargetPageCache] 目标页缓存检查', {
newPage, targetPage,
targetPageStartIndex, targetPageStartIndex,
targetPageEndIndex, targetPageEndIndex,
targetPageDataLength: targetPageData.length, targetPageDataLength: targetPageData.length,
@@ -89,32 +80,63 @@ const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast })
isTargetPageCached isTargetPageCached
}); });
// 1. 判断翻页类型:连续翻页(上一页/下一页)还是跳转翻页(点击页码/输入跳转) return {
const isSequentialNavigation = Math.abs(newPage - currentPage) === 1; isTargetPageCached,
targetPageInfo: {
startIndex: targetPageStartIndex,
endIndex: targetPageEndIndex,
validCount: validTargetData.length,
expectedCount
}
};
}, [allCachedEvents, pageSize, total]);
/**
* 子函数2: 计算预加载范围
* @param {number} targetPage - 目标页码
* @param {number} fromPage - 来源页码
* @returns {Array<number>} 预加载页码数组
*/
const calculatePreloadRange = useCallback((targetPage, fromPage) => {
const isSequentialNavigation = Math.abs(targetPage - fromPage) === 1;
// 2. 计算预加载范围
let preloadRange; let preloadRange;
if (isSequentialNavigation) { if (isSequentialNavigation) {
// 连续翻页前后各2页共5页 // 连续翻页前后各2页共5页
const start = Math.max(1, newPage - 2); const start = Math.max(1, targetPage - 2);
const end = Math.min(totalPages, newPage + 2); const end = Math.min(totalPages, targetPage + 2);
preloadRange = Array.from( preloadRange = Array.from(
{ length: end - start + 1 }, { length: end - start + 1 },
(_, i) => start + i (_, i) => start + i
); );
} else { } else {
// 跳转翻页:只加载当前页 // 跳转翻页:只加载当前页
preloadRange = [newPage]; preloadRange = [targetPage];
} }
// 3. 检查哪些页面的数据还未缓存(检查是否包含 null 或超出数组长度) console.log('[calculatePreloadRange] 计算预加载范围', {
targetPage,
fromPage,
isSequentialNavigation,
preloadRange
});
return preloadRange;
}, [totalPages]);
/**
* 子函数3: 查找缺失页面
* @param {Array<number>} preloadRange - 预加载范围
* @returns {Array<number>} 缺失页码数组
*/
const findMissingPages = useCallback((preloadRange) => {
const missingPages = preloadRange.filter(page => { const missingPages = preloadRange.filter(page => {
const pageStartIndex = (page - 1) * pageSize; const pageStartIndex = (page - 1) * pageSize;
const pageEndIndex = pageStartIndex + pageSize; const pageEndIndex = pageStartIndex + pageSize;
// 如果该页超出数组范围,说明未缓存 // 如果该页超出数组范围,说明未缓存
if (pageEndIndex > allCachedEvents.length) { if (pageEndIndex > allCachedEvents.length) {
console.log(`[missingPages] 页面${page}超出数组范围`, { console.log(`[findMissingPages] 页面${page}超出数组范围`, {
pageStartIndex, pageStartIndex,
pageEndIndex, pageEndIndex,
allCachedEventsLength: allCachedEvents.length allCachedEventsLength: allCachedEvents.length
@@ -128,7 +150,7 @@ const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast })
const expectedCount = Math.min(pageSize, total - pageStartIndex); const expectedCount = Math.min(pageSize, total - pageStartIndex);
const hasNullOrIncomplete = validData.length < expectedCount; const hasNullOrIncomplete = validData.length < expectedCount;
console.log(`[missingPages] 页面${page}检查`, { console.log(`[findMissingPages] 页面${page}检查`, {
pageStartIndex, pageStartIndex,
pageEndIndex, pageEndIndex,
pageDataLength: pageData.length, pageDataLength: pageData.length,
@@ -140,33 +162,40 @@ const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast })
return hasNullOrIncomplete; return hasNullOrIncomplete;
}); });
console.log('[handlePageChange] 缺失页面检测完成', { console.log('[findMissingPages] 缺失页面检测完成', {
preloadRange, preloadRange,
missingPages, missingPages,
missingPagesCount: missingPages.length missingPagesCount: missingPages.length
}); });
// 4. 如果目标页已缓存,立即切换页码,然后在后台静默预加载其他页 return missingPages;
if (isTargetPageCached && missingPages.length > 0 && hasMore) { }, [allCachedEvents, pageSize, total]);
console.log('[DynamicNewsCard] 目标页已缓存,立即切换', {
currentPage,
newPage,
缺失页面: missingPages,
目标页已缓存: true
});
// 立即切换页码(用户无感知延迟) /**
setCurrentPage(newPage); * 子函数4: 加载页面数据
* @param {Array<number>} missingPages - 缺失页码数组
* @param {number} targetPage - 目标页码
* @param {boolean} silentMode - 静默模式(后台预加载)
* @returns {Promise<boolean>} 是否加载成功
*/
const loadPages = useCallback(async (missingPages, targetPage, silentMode = false) => {
if (!silentMode) {
// 显示 loading 状态
setLoadingPage(targetPage);
}
// 在后台静默预加载其他缺失页面(拆分为单页请求)
try { try {
console.log('[DynamicNewsCard] 开始后台预加载', { console.log(`[loadPages] 开始加载`, {
缺失页面: missingPages, missingPages,
每页数量: pageSize targetPage,
silentMode,
pageSize
}); });
// 拆分为单页请求,避免 per_page 动态值导致后端返回空数据 // 拆分为单页请求,避免 per_page 动态值导致后端返回空数据
for (const page of missingPages) { for (const page of missingPages) {
console.log(`[loadPages] 开始加载第 ${page}`);
await dispatch(fetchDynamicNews({ await dispatch(fetchDynamicNews({
page: page, page: page,
per_page: pageSize, // 固定值5或10不使用动态计算 per_page: pageSize, // 固定值5或10不使用动态计算
@@ -174,86 +203,96 @@ const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast })
clearCache: false clearCache: false
})).unwrap(); })).unwrap();
console.log(`[DynamicNewsCard] 后台预加载${page} 页完成`); console.log(`[loadPages] ${page}加载完成`);
} }
console.log('[DynamicNewsCard] 后台预加载全部完成', { console.log('[loadPages] 所有页面加载完成', {
预加载页面: missingPages missingPages,
silentMode
}); });
return true;
} catch (error) { } catch (error) {
console.error('[DynamicNewsCard] 后台预加载失败', error); console.error('[loadPages] 加载失败', error);
// 静默失败,不影响用户体验
}
return; // 提前返回,不执行下面的加载逻辑 if (!silentMode) {
} // 非静默模式下显示错误提示
// 5. 如果目标页未缓存,显示 loading 并等待加载完成
if (missingPages.length > 0 && hasMore) {
console.log('[DynamicNewsCard] 目标页未缓存显示loading', {
currentPage,
newPage,
翻页类型: isSequentialNavigation ? '连续翻页' : '跳转翻页',
预加载范围: preloadRange,
缺失页面: missingPages,
每页数量: pageSize,
目标页已缓存: false
});
try {
// 设置加载状态(显示"正在加载第X页..."
setLoadingPage(newPage);
// 拆分为单页请求,避免 per_page 动态值导致后端返回空数据
for (const page of missingPages) {
console.log(`[DynamicNewsCard] 开始加载第 ${page}`);
await dispatch(fetchDynamicNews({
page: page,
per_page: pageSize, // 固定值5或10不使用动态计算
pageSize: pageSize, // 传递原始 pageSize用于正确计算索引
clearCache: false
})).unwrap();
console.log(`[DynamicNewsCard] 第 ${page} 页加载完成`);
}
console.log('[DynamicNewsCard] 所有缺失页面加载完成', {
缺失页面: missingPages
});
// 数据加载成功后才更新当前页码
setCurrentPage(newPage);
} catch (error) {
console.error('[DynamicNewsCard] 翻页加载失败', error);
// 显示错误提示
toast({ toast({
title: '加载失败', title: '加载失败',
description: `无法加载第 ${newPage} 页数据,请稍后重试`, description: `无法加载第 ${targetPage} 页数据,请稍后重试`,
status: 'error', status: 'error',
duration: 3000, duration: 3000,
isClosable: true, isClosable: true,
position: 'top' position: 'top'
}); });
}
// 加载失败时不更新页码,保持在当前页 return false;
} finally { } finally {
if (!silentMode) {
// 清除加载状态 // 清除加载状态
setLoadingPage(null); setLoadingPage(null);
} }
}
}, [dispatch, pageSize, toast]);
// 翻页处理(智能预加载)- 使用子函数重构
const handlePageChange = useCallback(async (newPage) => {
// 🔍 诊断日志 - 记录翻页开始状态
console.log('[handlePageChange] 开始翻页', {
currentPage,
newPage,
pageSize,
totalPages,
hasMore,
total,
allCachedEventsLength: allCachedEvents.length,
cachedCount
});
// 步骤1: 检查目标页缓存状态
const { isTargetPageCached } = checkTargetPageCache(newPage);
// 步骤2: 计算预加载范围
const preloadRange = calculatePreloadRange(newPage, currentPage);
// 步骤3: 查找缺失页面
const missingPages = findMissingPages(preloadRange);
// 步骤4: 根据情况加载数据
if (isTargetPageCached && missingPages.length > 0 && hasMore) {
// 场景A: 目标页已缓存,立即切换,后台静默预加载其他页
console.log('[handlePageChange] 目标页已缓存,立即切换 + 后台预加载', {
currentPage,
newPage,
缺失页面: missingPages
});
setCurrentPage(newPage);
await loadPages(missingPages, newPage, true); // 静默模式
} else if (missingPages.length > 0 && hasMore) {
// 场景B: 目标页未缓存,显示 loading 并等待加载完成
console.log('[handlePageChange] 目标页未缓存,显示 loading', {
currentPage,
newPage,
缺失页面: missingPages
});
const success = await loadPages(missingPages, newPage, false); // 非静默模式
if (success) {
setCurrentPage(newPage);
}
} else if (missingPages.length === 0) { } else if (missingPages.length === 0) {
// 只有在确实不需要加载时才直接切换 // 场景C: 所有页面均已缓存,直接切换
console.log('[handlePageChange] 无需加载,直接切换', { console.log('[handlePageChange] 无需加载,直接切换', {
currentPage, currentPage,
newPage, newPage,
preloadRange,
missingPages,
reason: '所有页面均已缓存' reason: '所有页面均已缓存'
}); });
setCurrentPage(newPage); setCurrentPage(newPage);
} else { } else {
// 理论上不应该到这里missingPages.length > 0 但 hasMore=false // 场景D: 意外分支(有缺失页面但 hasMore=false
console.warn('[handlePageChange] 意外分支:有缺失页面但无法加载', { console.warn('[handlePageChange] 意外分支:有缺失页面但无法加载', {
missingPages, missingPages,
hasMore, hasMore,
@@ -263,7 +302,6 @@ const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast })
cachedCount cachedCount
}); });
// 尝试切换页码,但可能会显示空数据
setCurrentPage(newPage); setCurrentPage(newPage);
toast({ toast({
@@ -275,7 +313,20 @@ const usePagination = ({ allCachedEvents, total, cachedCount, dispatch, toast })
position: 'top' position: 'top'
}); });
} }
}, [currentPage, allCachedEvents, pageSize, totalPages, hasMore, dispatch, total, toast, cachedCount]); }, [
currentPage,
pageSize,
totalPages,
hasMore,
total,
allCachedEvents.length,
cachedCount,
checkTargetPageCache,
calculatePreloadRange,
findMissingPages,
loadPages,
toast
]);
// 模式切换处理 // 模式切换处理
const handleModeToggle = useCallback((newMode) => { const handleModeToggle = useCallback((newMode) => {