You need to enable JavaScript to run this app. React Redux项目调用API时react-infinite-scroll无限滚动失效如何解决
优惠活动
大模型
产品
解决方案
定价
更多

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替换为数据唯一idpost.id,避免用index作为key引发的列表渲染异常
  • 移除冗余的useDispatch调用,统一用props注入的fetchHomePosts方法
  • 新增hasMore状态控制,后续可以根据接口返回的总数据量判断是否还有下一页,避免无用请求

内容的提问来源于stack exchange,提问作者Aadhit Shanmugam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 13:15:02