startTransition无法阻止React Native中Suspense触发加载状态
React Native中Suspense配合startTransition阻止fallback失效的解决方案
问题重现
使用Expo v49.0.0构建React Native v0.72.4应用时,在useSuspenseQuery的fetchMore调用外层包裹startTransition,原本预期能阻止组件触发Suspense的fallback加载状态(Web环境下正常生效),但在React Native中无论是否使用transition,执行loadMore时组件都会回到加载状态。
相关代码片段:
function Container({ navigation, }: ContainerProps): JSX.Element { const { ctx } = useTopTabContext(); const { address } = ctx; const [page, setPage] = useState(1); const { client, data, fetchMore } = useSuspenseQuery( QUERY, { fetchPolicy: "cache-and-network", variables: { address, filters: { limit: 100, }, }, } ); const loadMore = () => { if (data?.wallet?.items?.pageInfo.hasNextPage) { const nextPage = page + 1; startTransition(() => { fetchMore({ variables: { filters: { limit: 100, page: nextPage, }, }, }).then(() => { setPage(nextPage); }); }); } }; // ...其余代码 }
可能的解决方案
1. 切换到useQuery而非useSuspenseQuery
useSuspenseQuery的设计逻辑是只要查询处于pending状态就会触发Suspense,即使在transition中。换成普通的useQuery,手动管理加载状态,这样可以完全控制何时显示加载UI,避免Suspense自动触发fallback:
const { data, fetchMore, isFetching } = useQuery(QUERY, { fetchPolicy: "cache-and-network", variables: { address, filters: { limit: 100 }, }, }); const loadMore = () => { if (data?.wallet?.items?.pageInfo.hasNextPage) { const nextPage = page + 1; startTransition(() => { fetchMore({ variables: { filters: { limit: 100, page: nextPage }, }, }).then(() => setPage(nextPage)); }); } };
之后在渲染时,仅在初始加载阶段显示全局fallback,加载更多时用列表底部的局部加载提示替代,不再依赖Suspense的自动触发逻辑。
2. 调整Apollo Client的fetchPolicy
尝试将fetchPolicy改为"cache-first"或"network-only"(根据业务需求选择):
cache-first会优先使用缓存数据,只有缓存不存在时才发起网络请求,能避免加载更多时因网络请求触发Suspense;network-only强制走网络,但可以配合手动状态管理控制加载UI的显示时机。
3. 绕过Suspense,手动管理加载状态
在组件内新增加载状态变量,完全接管加载逻辑,不让Suspense干预加载更多的过程:
const [isLoadingMore, setIsLoadingMore] = useState(false); const loadMore = () => { if (data?.wallet?.items?.pageInfo.hasNextPage && !isLoadingMore) { const nextPage = page + 1; startTransition(() => { setIsLoadingMore(true); fetchMore({ variables: { filters: { limit: 100, page: nextPage } }, }).then(() => { setPage(nextPage); setIsLoadingMore(false); }); }); } };
然后在FlashList的尾部渲染isLoadingMore对应的加载组件即可。
4. 检查Apollo Client版本兼容性
确保@apollo/client版本与React Native、React版本匹配,比如v3.8+版本对React 18的Suspense支持更完善,若当前使用旧版本,升级到兼容的最新版本可能解决问题。
内容的提问来源于stack exchange,提问作者m_callens
相关产品推荐
相关产品推荐

