如何将useSWR返回的data存入useState实现无限滚动数据拼接
问题结论
你提供的写法不可行。
不可行的原因
useState的初始值仅会在组件首次渲染时赋值一次,而useSWR发起的是异步网络请求,首次渲染时请求还未返回,data的值为undefined,因此memes的初始值会被设为undefined。后续useSWR请求成功拿到最新的data时,也不会主动触发useState重新赋值,你无法拿到最新的请求数据用于后续拼接。
正确实现方案
方案1:基于现有写法修正
通过useEffect监听useSWR返回的data变化,请求成功后将新数据追加到useState维护的列表中,示例代码如下:
import { useState, useEffect } from 'react'; import useSWR from 'swr'; const fetcher = (url: string) => fetch(url).then((r) => r.json()); function MemeList() { // 维护分页页码,滚动到底部时更新页码触发新请求 const [page, setPage] = useState(1); // 存储拼接后的全量列表数据 const [memes, setMemes] = useState([]); const { data, error, isLoading } = useSWR( // 页码作为请求参数的一部分,页码变化时自动发起新请求 `https://meme-api.herokuapp.com/gimme/5?page=${page}`, fetcher, ); // 监听请求返回的data,有新数据时拼到原有列表末尾 useEffect(() => { // 此处字段需根据你的接口实际返回结构调整 if (data?.memes?.length) { setMemes(prevList => [...prevList, ...data.memes]); } }, [data]); // 无限滚动触发逻辑示例:监听滚动容器滚动到底部时调用 setPage(prev => prev + 1) // 可根据业务需求补充loading、错误状态的渲染逻辑 return ( <div> {memes.map(meme => <img key={meme.id} src={meme.url} alt={meme.caption} />)} {isLoading && <div>加载中...</div>} </div> ) }
方案2:使用SWR官方无限滚动专用钩子
SWR官方提供了useSWRInfinite钩子,原生封装了分页数据拼接、加载状态管理、重复请求拦截等能力,更适合无限滚动场景,不需要手动维护useState做数据合并。示例代码如下:
import useSWRInfinite from 'swr/infinite'; const fetcher = (url: string) => fetch(url).then((r) => r.json()); function MemeList() { const { data, error, isLoading, setSize } = useSWRInfinite( (pageIndex) => `https://meme-api.herokuapp.com/gimme/5?page=${pageIndex + 1}`, fetcher ); // 所有页的拼接数据,直接拿flat之后的结果即可 const memes = data ? data.flatMap(page => page.memes) : []; // 滚动到底部时调用 setSize(prev => prev + 1) 即可加载下一页 return ( <div> {memes.map(meme => <img key={meme.id} src={meme.url} alt={meme.caption} />)} {isLoading && <div>加载中...</div>} </div> ) }
内容的提问来源于stack exchange,提问作者Jatin Hemnani
相关产品推荐
相关产品推荐

