Next.js中的无限滚动使第一个获取的最后一个元素加倍
我有一个基于Next.js从Strapi Rest API提取的项目。我正在根据获取的内容获取和渲染卡。由于我不想使用 react-infinite-react-infinite- -scroller 。它可以正常工作,我唯一的问题是,基于元素的数量,有时,最后一个对象会返回agagain,而不是下一页的第一个对象。这仅在用户首次到达页面底部时,仅在无限加载程序的第一个提取呼叫上发生。
初始获取:
export async function getServerSideProps({locale}, ctx) {
const jwt = parseCookies(ctx).jwt
if (jwt) {
const articlesArray = await getArticles({locale}, jwt, 0, 10)
const articles = articlesArray.articlesList
const total = articlesArray.total
const cookieJwt = jwt
return {
props: {
articles,
cookieJwt,
total
},
}
}
// I DELETED THE AUTH LOGIC HERE
GetArticles功能:
import qs from 'qs'
export async function getArticles({locale}, jwt,page, size) {
const query = qs.stringify({
pagination: {
start: page,
limit: size,
},
sort: ['date:desc'],
},
{
encodeValuesOnly: true,
});
const fetchArticles = await fetch(`${process.env.DB_HOST}/api/articles?locale=${locale}&populate=*&${query}`,
{
headers: {
Authorization: `Bearer ${jwt}`
}
})
const articles = await fetchArticles.json()
const articlesArray = {
articlesList: articles.data ,
total: articles.meta.pagination.total
}
return articlesArray
}
无限滚动组件:
<InfiniteScroll
pageStart={0}
loadMore={getMorePost}
hasMore={hasMore}
loader={<div className={cardStyle.loaderWrapper}><div className={cardStyle.loader}><Loader color={'orange'} variant={'bars'} /></div></div>}
>
<SimpleGrid cols={3}
spacing={"xl"}
breakpoints={[
{ maxWidth: 1200, cols: 2, spacing: 'md' },
{ maxWidth: 755, cols: 1, spacing: 'sm' },
]}>
{posts.map((article) => {
return(
<ArticleCard key={newKey()} data={article} locale={locale} onClick={() => handleClick(article)} />
)
}
)}
</SimpleGrid>
</InfiniteScroll>
GetMorePosts功能:
const getMorePost = async () => {
if(pageCounter < total){
const res = await getArticles({locale},cookieJwt, pageCounter , 10)
setPageCounter(pageCounter + 10)
const newPosts = res.articlesList;
setPosts((post) => [...post, ...newPosts]);
}
else {
setHasMore(false)
}
};
据我所知,应该加载前10个元素,并且GetMorePost应该加载10个下一个元素。但是,这并不是完全发生的
可以找到完整的页面在 repo
I have a project that is based on Next.js fetching from Strapi Rest API. I'm fetching and rendering cards based on the content on the fetch. Since I don't want to load everything at once I implemented an infinite scroll using react-infinite-scroller . It works fine, my only problem is that based on the amount of elements, sometimes, the last object gets returnedagain instead of the first of the next page. This only happens on the first fetch call of the infinite loader when the user reaches the bottom of the page for the first time.
initial fetch :
export async function getServerSideProps({locale}, ctx) {
const jwt = parseCookies(ctx).jwt
if (jwt) {
const articlesArray = await getArticles({locale}, jwt, 0, 10)
const articles = articlesArray.articlesList
const total = articlesArray.total
const cookieJwt = jwt
return {
props: {
articles,
cookieJwt,
total
},
}
}
// I DELETED THE AUTH LOGIC HERE
GetArticles function :
import qs from 'qs'
export async function getArticles({locale}, jwt,page, size) {
const query = qs.stringify({
pagination: {
start: page,
limit: size,
},
sort: ['date:desc'],
},
{
encodeValuesOnly: true,
});
const fetchArticles = await fetch(`${process.env.DB_HOST}/api/articles?locale=${locale}&populate=*&${query}`,
{
headers: {
Authorization: `Bearer ${jwt}`
}
})
const articles = await fetchArticles.json()
const articlesArray = {
articlesList: articles.data ,
total: articles.meta.pagination.total
}
return articlesArray
}
Infinite scroll component :
<InfiniteScroll
pageStart={0}
loadMore={getMorePost}
hasMore={hasMore}
loader={<div className={cardStyle.loaderWrapper}><div className={cardStyle.loader}><Loader color={'orange'} variant={'bars'} /></div></div>}
>
<SimpleGrid cols={3}
spacing={"xl"}
breakpoints={[
{ maxWidth: 1200, cols: 2, spacing: 'md' },
{ maxWidth: 755, cols: 1, spacing: 'sm' },
]}>
{posts.map((article) => {
return(
<ArticleCard key={newKey()} data={article} locale={locale} onClick={() => handleClick(article)} />
)
}
)}
</SimpleGrid>
</InfiniteScroll>
GetMorePosts function :
const getMorePost = async () => {
if(pageCounter < total){
const res = await getArticles({locale},cookieJwt, pageCounter , 10)
setPageCounter(pageCounter + 10)
const newPosts = res.articlesList;
setPosts((post) => [...post, ...newPosts]);
}
else {
setHasMore(false)
}
};
As far as I can tell the first 10 elements should be loaded and the getMorePost should load the 10 next ones. However that's not exactly what happens
the behavior can be observed here
The full page can be found on the repo
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我认为这个问题的快速解决方法可能是使用lodash的
_。uniqby()
method( https://lodash.com/docs/4.17.15#uniqby )。这将为您提供19个重新加载的19个显示,但至少可以确保您没有任何重复的项目。我认为真正的解决方案是弄清楚为什么API返回第10个项目两次。在尝试从数据库中获取原始查询时,起始值似乎可能是不正确的。
使用Burp Suite并与代理拦截器一起玩,看起来查询最终看起来像这样的东西:
/api/cratce?locale = en&amp; populate =*&amp;分页[start] = 10&amp;分页[limit] = 10&amp; sort [0] = date%3ADESC
。我认为,如果您碰到分页[启动] 1,那应该实际上可以解决您的问题。至少对我做了。I think a quick fix to this issue could be using something like lodash's
_.uniqBy()
method (https://lodash.com/docs/4.17.15#uniqBy). That will give you a total of 19 to display on the first reload, but it would at least ensure that you don't have any duplicate items.I think the real fix is to figure out why the API is returning that 10th item twice; it seems like the starting value might be incorrect when trying to grab from the database for the original query.
Using burp suite and playing with the proxy interceptor, it looks like the query ends up looking something like this:
/api/articles?locale=en&populate=*&pagination[start]=10&pagination[limit]=10&sort[0]=date%3Adesc
. I think if you bump up the pagination[start] by 1, that should actually fix your problem. It did for me at least.