如何将RTK Query响应与缓存数据追加整合,实现FlatList无限滚动并支持重取替换?
用RTK Query实现FlatList无限滚动的数据合并与重取替换
要实现无限滚动时合并新旧数据、重取时替换现有数据的需求,你可以通过两种方式处理:利用RTK Query的内置缓存配置,或者在组件内维护本地状态。以下是具体实现方案:
方案一:通过RTK Query的API配置实现全局缓存合并
这种方式适合需要全局共享分页数据的场景,不需要在组件内额外维护状态。
1. 修改API定义,配置合并与重取规则
首先在你的createApi定义中,给分页查询添加merge和forceRefetchBehavior配置:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'; export const postsApi = createApi({ reducerPath: 'postsApi', baseQuery: fetchBaseQuery({ baseUrl: '/api/' }), endpoints: (builder) => ({ getPosts: builder.query({ // 传入分页参数:page(当前页)、limit(每页条数)、refresh(是否触发全量替换) query: ({ page, limit, refresh }) => `posts?page=${page}&limit=${limit}`, // 合并逻辑:新请求的分页数据追加到现有缓存末尾 merge: (currentCache, newResponse) => { // 如果后端返回的是数组直接合并;如果是包含data的对象,调整为currentCache.data.push(...newResponse.data) currentCache.push(...newResponse); }, // 重取替换规则:当refresh为true或首次请求时,用新数据完全替换旧缓存 forceRefetch({ currentArg, previousArg }) { return currentArg?.refresh || !previousArg; }, // 缓存保留时间,按需设置 keepUnusedDataFor: 60, }), }), }); export const { useGetPostsQuery } = postsApi;
2. 组件内使用查询,处理无限滚动与刷新
在FlatList组件中维护分页状态,触发请求并处理刷新逻辑:
import { useState } from 'react'; import { FlatList, ActivityIndicator } from 'react-native'; import { useGetPostsQuery } from './postsApi'; const PostList = () => { const [currentPage, setCurrentPage] = useState(1); const [isRefreshing, setIsRefreshing] = useState(false); // 传入分页参数,refresh为true时触发全量替换 const { data: posts, isLoading, isFetching } = useGetPostsQuery( { page: currentPage, limit: 10, refresh: isRefreshing }, { refetchOnMountOrArgChange: isRefreshing } ); // 下拉刷新:重置页码并触发全量替换 const handleRefresh = () => { setIsRefreshing(true); setCurrentPage(1); // 请求完成后重置刷新状态 setTimeout(() => setIsRefreshing(false), 1000); }; // 滚动到底部加载下一页 const handleLoadMore = () => { if (!isLoading && !isFetching) { setCurrentPage(prev => prev + 1); } }; return ( <FlatList data={posts || []} renderItem={({ item }) => <PostItem post={item} />} keyExtractor={item => item.id.toString()} onRefresh={handleRefresh} refreshing={isRefreshing} onEndReached={handleLoadMore} onEndReachedThreshold={0.1} ListFooterComponent={isFetching ? <ActivityIndicator /> : null} /> ); }; export default PostList;
方案二:组件内维护本地状态合并数据
如果不需要全局共享缓存,只在当前组件内处理数据合并,这种方式更灵活:
import { useState, useEffect } from 'react'; import { FlatList, ActivityIndicator } from 'react-native'; import { useGetPostsQuery } from './postsApi'; const PostList = () => { const [currentPage, setCurrentPage] = useState(1); const [allPosts, setAllPosts] = useState([]); const [isRefreshing, setIsRefreshing] = useState(false); const { data: newPosts, isLoading, isFetching } = useGetPostsQuery({ page: currentPage, limit: 10 }); // 监听新数据,合并或替换本地状态 useEffect(() => { if (newPosts) { if (currentPage === 1 || isRefreshing) { // 第一页或刷新时,用新数据替换全部 setAllPosts(newPosts); setIsRefreshing(false); } else { // 加载更多时,追加新数据 setAllPosts(prev => [...prev, ...newPosts]); } } }, [newPosts, currentPage, isRefreshing]); const handleRefresh = () => { setIsRefreshing(true); setCurrentPage(1); }; const handleLoadMore = () => { if (!isLoading && !isFetching) { setCurrentPage(prev => prev + 1); } }; return ( <FlatList data={allPosts} renderItem={({ item }) => <PostItem post={item} />} keyExtractor={item => item.id.toString()} onRefresh={handleRefresh} refreshing={isRefreshing} onEndReached={handleLoadMore} onEndReachedThreshold={0.1} ListFooterComponent={isFetching ? <ActivityIndicator /> : null} /> ); }; export default PostList;
注意事项
- 确保你的后端接口支持分页参数(如
page、limit),返回对应页的数据列表。 - 如果后端返回的是包含总条数、数据列表的对象(如
{ data: [], total: 100 }),需要调整merge函数或本地状态的合并逻辑,对应处理newPosts.data这类结构。 - 方案一中的
forceRefetch规则可根据实际需求修改,比如当页码回到1时自动触发全量替换。
内容的提问来源于stack exchange,提问作者basil
相关产品推荐
相关产品推荐

