You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

react-infinite-scroll-component与Material UI Grid无限滚动失效问题

问题描述

我在应用首页展示用户帖子,共有约45条模拟数据,使用react-infinite-scroll-component每次加载5条。但实际仅能显示10-15条,之后滚动组件停留在“Loading...”状态不再加载。我将Material UI的Grid作为InfiniteScroll的子组件,疑惑二者是否兼容?同时state的使用方式是否会影响该功能?

相关代码

获取更多数据的函数

const fetchMoreData = (e) => {
  e.preventDefault()
  if (numberOfPosts.length >= 45) {
    setHasMore(false)
    return;
  }

  setTimeout(() => {
    setNumberOfPosts(numberOfPosts.concat(Array.from({length: 5})))
  }, 500)
}

无限滚动组件代码

<InfiniteScroll dataLength={numberOfPosts.length} next={fetchMoreData} hasMore={hasMore} loader={<h4>Loading...</h4>}
       id='all-post-container' scrollThreshold={1} endMessage={<p style={{ textAlign: "center" }}>
       <b>Yay! You have seen it all</b>
     </p>}
       style={{position: 'absolute', top: '25%', left: '20%', backgroundColor: 'red', height: '72%', width: "54%", borderRadius: '30px'}}>
      <Grid
        container
        direction="column"
        justifyContent="center"
        alignItems="center"
        spacing={45}
      >
      {numberOfPosts.map(key => {
      return (
        <Grid container item>
        <div id="post-container" style={{margin: '5%', position: 'absolute', width: '90%', height: '40%', backgroundColor: 'white', borderRadius: '30px', overflow: 'auto'}}>
          <Avatar src={<AvatarPicture/>} style={{position: 'absolute', left: '1%', top: '3%', height: '60px', width: '60px'}} size='lg'></Avatar>
          <p style={{position: 'absolute', left: '9%', top: '-5%', fontFamily: 'Outfit', fontStyle: 'normal', fontWeight: '500', fontSize: '20px', lineHeight: '25px', overflow: 'auto'}}>@{state.storage.username}</p>
          <p style={{position: 'absolute', left: '9%', top: '10%', fontFamily: 'Outfit', fontStyle: 'normal', fontWeight: '400', fontSize: '16px', lineHeight: '20px', color: '#6D7683'}}>{state.storage.location}</p>
          <p style={{position: 'absolute', left: '20%', top: '10%', fontFamily: 'Outfit', fontStyle: 'normal', fontWeight: '400', fontSize: '16px', lineHeight: '20px', color: '#2D87FF'}}>time</p>
          <div id="text-container" style={{position: 'absolute', top: '30%', left: '5%', backgroundColor: '#FFFBEE', height: '30%', width: '90%', borderRadius: '16px'}}></div>
          <TextField InputProps={{
            startAdornment: (
              <InputAdornment>
                <Avatar src={state.storage.profileImageURL} />
              </InputAdornment>
            ),
            classes: {
              notchedOutline: 'notched-outline-border-radius'
          }
          }} maxRows={10} inputProps={{maxLength: 500}} multiline style={{position: 'absolute', left: '5%', top: '78%', width: '90%', background: '#F8FAFF', border: '1px solid #D9E1F9', borderRadius: '16px'}} placeholder='Write your comment'></TextField>
          <IconButton onClick={() => setLike(!like)} style={{ position: 'absolute', top: '60%', left: '5%'}} onMouseLeave={() => setMouseOver(false)} onMouseOver={() => setMouseOver(true)}>{like && mouseOver ? <HeartBrokenIcon style={{color: 'red'}}/> : like ? <FavoriteIcon style={{color: 'red'}} /> : <FavoriteBorderTwoToneIcon /> }</IconButton>
          <p style={{position: 'absolute', top: '59%', left: '9%'}}>likes</p>
          <IconButton onClick={() => setReply(!reply)} style={{ position: 'absolute', top: '60%', left: '13%'}}>{reply ? <MessageIcon color="primary"/> : <MessageOutlinedIcon/>}</IconButton>
          <p style={{position: 'absolute', top: '59%', left: '17%'}}>replies</p>
          <IconButton style={{ position: 'absolute', top: '60%', left: '23%'}}><IosShareOutlinedIcon /></IconButton>
          <p style={{position: 'absolute', top: '59%', left: '27%'}}>shares</p>
        </div>
        </Grid>
      )})}
      </Grid>
      </InfiniteScroll>

问题原因及修复方案

1. State更新的闭包陷阱

你在fetchMoreData里直接用numberOfPosts.concat更新state,这里存在闭包问题——每次调用函数时,numberOfPosts都是函数创建时的旧值,导致后续数据无法正确累加,到一定次数后就无法触发新的加载。

修复: 使用函数式更新获取最新的state值:

const fetchMoreData = (e) => {
  e.preventDefault()
  if (numberOfPosts.length >= 45) {
    setHasMore(false)
    return;
  }

  setTimeout(() => {
    // 用prevPosts拿到最新的状态
    setNumberOfPosts(prevPosts => prevPosts.concat(Array.from({length: 5})))
  }, 500)
}

2. 绝对定位破坏布局高度计算

你的帖子容器#post-container使用了position: absolute,这会让Grid无法正确计算内容的实际高度,导致InfiniteScroll错误判断已经滚动到底部,停止触发加载。

修复:

  • 移除#post-container的position: absolute,改用margin、padding或Grid的spacing来控制元素间距
  • 确保InfiniteScroll的容器内的子元素(Grid)能正常撑开容器高度,让滚动事件被正确检测

3. Material UI Grid与InfiniteScroll的兼容性

二者本身完全兼容,但你设置的spacing={45}值过大,加上子元素的绝对定位,会导致布局混乱,影响InfiniteScroll的滚动检测逻辑。

建议:

  • 把Grid的spacing调整为合理值(比如2、3)
  • 避免子元素使用绝对定位破坏Grid的正常布局流

额外检查项

  • 确认hasMore的初始值为true
  • 调整scrollThreshold为默认的0.8(设为1需要滚动到最底部才触发,容易出现检测延迟或失效)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 13:17:02