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

React Native中FlatList的scrollToIndex索引越界异常排查

问题分析与解决

错误原因

你遇到的scrollToIndex out of range错误,核心是FlatList多列模式下getItemLayout的偏移量计算逻辑错误:

  • 你设置了numColumns={7},意味着每行显示7天,但getItemLayout中直接用item索引 × 行高计算偏移量,相当于把每个item当成独立一行,导致偏移量被放大7倍。
  • 当请求滚动到index365时,FlatList根据错误的偏移量计算,误以为需要滚动到365行,但实际总行数仅约110行(761÷7),因此触发越界错误。

修复方案

1. 修正getItemLayout计算逻辑

多列模式下,偏移量需基于行索引而非item索引,修改如下:

getItemLayout={(data, index) => {
  const rowHeight = MONTH_HEIGHT / 6;
  const rowIndex = Math.floor(index / 7); // 计算当前item所在行
  return {
    length: rowHeight, // 单个item的垂直高度等于行高
    offset: rowHeight * rowIndex, // 偏移量为行索引×行高
    index,
  };
}}

2. 优化滚动逻辑(可选)

直接通过目标日期的行索引使用scrollToOffset,避免索引计算偏差:

useEffect(() => {
  if (days.length > 0 && listRef.current) {
    const timer = setTimeout(() => {
      const firstDayOfCurrentMonth = today.startOf('month');
      const index = days.findIndex(day => day.isSame(firstDayOfCurrentMonth, 'day'));
      if (index >= 0) {
        const rowHeight = MONTH_HEIGHT / 6;
        const rowIndex = Math.floor(index / 7);
        listRef.current.scrollToOffset({
          offset: rowIndex * rowHeight,
          animated: false,
        });
      }
    }, 100);

    return () => clearTimeout(timer);
  }
}, [days]);

3. 修复日期生成边界(可选)

原日期生成循环会漏掉结束当天,修改条件确保包含最后一天:

while (currentDate.isBefore(endDate) || currentDate.isSame(endDate, 'day')) {
  days.push(currentDate);
  currentDate = currentDate.add(1, 'day');
}

关键修改后的代码片段

// FlatList部分关键修改
<FlatList
  ref={listRef}
  data={days}
  keyExtractor={(item) => item.format("YYYY-MM-DD")}
  renderItem={/* 原有渲染逻辑 */}
  numColumns={7}
  columnWrapperStyle={styles.row}
  getItemLayout={(data, index) => {
    const rowHeight = MONTH_HEIGHT / 6;
    const rowIndex = Math.floor(index / 7);
    return {
      length: rowHeight,
      offset: rowHeight * rowIndex,
      index,
    };
  }}
  onViewableItemsChanged={onViewableItemsChanged}
  viewabilityConfig={{ itemVisiblePercentThreshold: 10 }}
  onScrollToIndexFailed={({ index, averageItemLength }) => {
    const rowHeight = MONTH_HEIGHT / 6;
    const rowIndex = Math.floor(index / 7);
    listRef.current?.scrollToOffset({
      offset: rowIndex * rowHeight,
      animated: false,
    });
  }}
/>

// 滚动逻辑修改
useEffect(() => {
  if (days.length > 0 && listRef.current) {
    const timer = setTimeout(() => {
      const firstDayOfCurrentMonth = today.startOf('month');
      const index = days.findIndex(day => day.isSame(firstDayOfCurrentMonth, 'day'));
      if (index >= 0) {
        const rowHeight = MONTH_HEIGHT / 6;
        const rowIndex = Math.floor(index / 7);
        listRef.current.scrollToOffset({
          offset: rowIndex * rowHeight,
          animated: false,
        });
      }
    }, 100);

    return () => clearTimeout(timer);
  }
}, [days]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 15:44:51