React Redux项目调用API时react-infinite-scroll无限滚动失效如何解决
核心问题梳理
- 违反Hook调用规则:
useEffect只能在React组件顶层作用域调用,你在普通函数MorePosts内部声明useEffect,直接触发Hook规则报错 - 偏移量
skipper是普通局部变量,组件每次重渲染都会被重置为0,无法正确记录下一次请求的起始位置 - 同时混用
connect高阶组件和useDispatch,属于冗余写法,你已经通过mapDispatchtoProps把fetchHomePosts注入到props里了,不需要额外调用useDispatch hasMore写死为true,后续所有数据加载完成后还会持续触发无用请求MorePosts里没有更新偏移量的逻辑,就算能正常请求,每次传的参数也是固定值,无法加载下一页数据
修复后完整代码
import React, { useEffect, useState } from 'react'; import './Homefeed.css'; import StickyNav from '../StickyNav/StickyNav'; import { fetchHomePosts } from '../Redux/HomeFeed-Redux/HomeFeedActionMethods'; import { connect } from 'react-redux'; import PostCell from '../PostCell/PostCell'; import InfiniteScroll from 'react-infinite-scroll-component'; function Homefeed({homeposts,fetchHomePosts}) { // 用useState存偏移量,不会随组件重渲染重置 const [skipper, setSkipper] = useState(0); // 存是否还有更多数据,实际可以和接口返回的总条数对比计算 const [hasMore, setHasMore] = useState(true); // 首次加载第一页 useEffect(()=>{ fetchHomePosts(skipper); },[fetchHomePosts, skipper]); // 滚动到底部触发的加载更多逻辑 function MorePosts(){ // 计算下一页的偏移量 const nextSkip = skipper + 10; // 这里可以加判断:如果当前已加载条数 >= 总条数,就setHasMore(false),终止加载 // 比如你接口返回总条数存在homeposts.total的话,可以这么写: // if(homeposts.homeposts.length >= homeposts.total) { // setHasMore(false); // return; // } setSkipper(nextSkip); fetchHomePosts(nextSkip); } return homeposts.isLoading ? (<h2>Loading...</h2>) : homeposts.error ? (<h3>{homeposts.error}</h3>) : ( <div className="homefeed-layout"> <title>Home Feed</title> <StickyNav /> <InfiniteScroll dataLength={homeposts.homeposts.length} hasMore={hasMore} loader={<h3>加载中...</h3>} next={MorePosts} // 直接传函数引用就行,不需要包一层匿名函数 > { homeposts.homeposts?.map((post,index)=> { var slug = post.attributes.title; slug = slug.replace(/\s/g, '-'); slug = slug.toLowerCase(); slug = slug.replace(/[^a-zA-Z0-9\-]/g, ''); slug = slug.replace(/(-)\1+/g, '-'); slug = slug.replace(/-$/, ''); slug = slug.replace(/^-/, ''); return( <div className="content-area" key={post.id} > {/* 不要用index做key,用数据唯一id性能更好 */} <PostCell key ={post.id} slug = {slug} postId = {post.id} title ={post.attributes.title} likes ={post.attributes.likes} comments ={post.attributes.comments} category ={post.attributes.category} postimageurl = {post.attributes.postImageURL} handle ={post.attributes.createdBy.attributes.handle} timestamp = {post.attributes.createdAt} subtitle = {post.attributes.subtitle} realName ={post.attributes.createdBy.attributes.realName} profileImage = {post.attributes.createdBy.attributes.profileImage?._url} followers = {post.attributes.createdBy.attributes.followers} posts = {post.attributes.createdBy.attributes.posts} name = {post.attributes.createdBy.attributes.name} /> </div> ) }) } </InfiniteScroll> </div> ) } const mapStatetoProps = (state) =>{ return{ homeposts:state.HomePosts } } const mapDispatchtoProps = (dispatch) =>{ return{ fetchHomePosts:(skipper)=>{dispatch(fetchHomePosts(skipper))}, } } export default connect(mapStatetoProps,mapDispatchtoProps) (Homefeed)
额外优化点说明
- 列表key替换为数据唯一id
post.id,避免用index作为key引发的列表渲染异常 - 移除冗余的
useDispatch调用,统一用props注入的fetchHomePosts方法 - 新增
hasMore状态控制,后续可以根据接口返回的总数据量判断是否还有下一页,避免无用请求
内容的提问来源于stack exchange,提问作者Aadhit Shanmugam
相关产品推荐
相关产品推荐

