refactor: standardize pagination response structure and enhance cursor handling
All checks were successful
Frontend CI / build-and-push-web (push) Successful in 5m8s
Frontend CI / ota-android (push) Successful in 11m22s
Frontend CI / build-android-apk (push) Successful in 45m46s

- Update various services and hooks to replace 'items' with 'list' for consistency in pagination responses.
- Modify PostRepository, commentService, groupService, messageService, and postService to align with the new response structure.
- Enhance cursor pagination logic in hooks and components to ensure proper handling of pagination states.
- Refactor HomeScreen, PostDetailScreen, SearchScreen, and other components to utilize the updated pagination structure.
This commit is contained in:
lafay
2026-03-23 03:58:26 +08:00
parent 88510aa6ae
commit 26ae288470
19 changed files with 312 additions and 309 deletions

View File

@@ -64,10 +64,14 @@ export interface PostsState {
hasMore: boolean;
/** 错误信息 */
error: string | null;
/** 当前游标 */
/** 当前游标cursor 模式) */
cursor: string | null;
/** 当前页码page 模式) */
currentPage: number;
/** 最后加载时间 */
lastLoadTime: number | null;
/** 上次请求的参数(用于加载更多和刷新) */
lastParams?: GetPostsParams;
}
/**
@@ -198,6 +202,7 @@ class ProcessPostUseCase {
hasMore: true,
error: null,
cursor: null,
currentPage: 1,
lastLoadTime: null,
};
this.postsState.set(key, state);
@@ -257,29 +262,32 @@ class ProcessPostUseCase {
* @param key 列表键(用于区分不同的列表)
*/
async fetchPosts(params?: GetPostsParams, key: string = 'default'): Promise<PostsResult> {
const state = this.getPostsState(key);
// 更新加载状态
this.updatePostsState(key, { isLoading: true, error: null });
try {
// 合并分页参数
// 默认传递空字符串 cursor 来启动 cursor 模式
// 注意cursor 要放在 ...params 后面,这样只有在 params 没有传 cursor 时才使用默认值
const queryParams: GetPostsParams = {
page: params?.page || 1,
pageSize: params?.pageSize || DEFAULT_PAGE_SIZE,
cursor: params?.cursor || state.cursor || undefined,
...params,
cursor: params?.cursor !== undefined ? params.cursor : '', // 默认使用空字符串启动 cursor 模式
};
const result = await postRepository.getPosts(queryParams);
// 更新状态
// 判断是否为 cursor 模式(有 next_cursor 返回)
const isCursorMode = result.nextCursor !== undefined && result.nextCursor !== null;
// 更新状态(保存请求参数以便加载更多时使用)
this.updatePostsState(key, {
posts: result.posts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
cursor: isCursorMode ? result.nextCursor : null, // cursor 模式保存 cursor否则设为 null 表示 page 模式
currentPage: isCursorMode ? undefined : 1, // page 模式从第 1 页开始
isLoading: false,
lastLoadTime: Date.now(),
lastParams: params, // 保存请求参数
});
// 通知订阅者
@@ -312,20 +320,29 @@ class ProcessPostUseCase {
* @param key 列表键
*/
async refreshPosts(key: string = 'default'): Promise<PostsResult> {
const state = this.getPostsState(key);
// 更新刷新状态
this.updatePostsState(key, { isRefreshing: true, error: null });
try {
// 使用保存的请求参数(如 post_type进行刷新
// 默认传递空字符串 cursor 来启动 cursor 模式
const result = await postRepository.getPosts({
page: 1,
pageSize: DEFAULT_PAGE_SIZE,
...state.lastParams,
cursor: state.lastParams?.cursor !== undefined ? state.lastParams.cursor : '', // 默认使用空字符串启动 cursor 模式
});
// 判断是否为 cursor 模式(有 next_cursor 返回)
const isCursorMode = result.nextCursor !== undefined && result.nextCursor !== null;
// 更新状态
this.updatePostsState(key, {
posts: result.posts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
cursor: isCursorMode ? result.nextCursor : null,
currentPage: isCursorMode ? undefined : 1,
isRefreshing: false,
lastLoadTime: Date.now(),
});
@@ -372,21 +389,45 @@ class ProcessPostUseCase {
this.updatePostsState(key, { isLoading: true, error: null });
try {
const queryParams: GetPostsParams = {
pageSize: DEFAULT_PAGE_SIZE,
cursor: state.cursor || undefined,
};
// 判断使用哪种分页模式cursor 不为 null 表示使用 cursor 模式
const useCursorMode = state.cursor !== null && state.cursor !== undefined;
// 必须先展开 lastParams再由本次分页字段覆盖。
// lastParams 来自首次 fetch通常含 page:1若写在展开之前会把 nextPage/cursor 覆盖掉,导致永远请求第 1 页、无法加载第 3 页及以后。
const base = { ...(state.lastParams ?? {}) } as GetPostsParams;
let queryParams: GetPostsParams;
if (useCursorMode) {
delete base.page;
queryParams = {
...base,
pageSize: DEFAULT_PAGE_SIZE,
cursor: state.cursor!,
};
} else {
const nextPage = (state.currentPage || 1) + 1;
delete base.cursor;
queryParams = {
...base,
pageSize: DEFAULT_PAGE_SIZE,
page: nextPage,
};
}
const result = await postRepository.getPosts(queryParams);
// 合并新数据
const newPosts = [...state.posts, ...result.posts];
// 判断响应是否为 cursor 模式(有 next_cursor 返回)
const responseIsCursorMode = result.nextCursor !== undefined && result.nextCursor !== null;
// 更新状态
this.updatePostsState(key, {
posts: newPosts,
hasMore: result.hasMore,
cursor: result.nextCursor || null,
cursor: responseIsCursorMode ? result.nextCursor : null,
currentPage: useCursorMode ? state.currentPage : ((state.currentPage || 1) + 1),
isLoading: false,
lastLoadTime: Date.now(),
});
@@ -398,6 +439,7 @@ class ProcessPostUseCase {
};
} catch (error) {
const errorMessage = error instanceof Error ? error.message : '加载更多帖子失败';
console.error('[ProcessPostUseCase] Load more error:', errorMessage);
this.updatePostsState(key, {
isLoading: false,
error: errorMessage,