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

React Native中如何调用API实现数据分页加载

React Native 对接指定分页API实现加载功能

分页字段规则先理清楚

先把接口返回的Pagination字段逻辑摸透,避免判断出错:

  • showing:结果范围提示文案,直接展示即可
  • data:分页操作项数组,每个项的字段含义:
    • name:操作项显示文本,固定值PREV代表上一页、NEXT代表下一页,其余值为页码
    • onclick:是否可点击,1=可点击,0=不可点击
    • value:点击后需要请求的目标页码
    • disabled:字符串包含disabled时代表当前项禁用
    • active:字符串包含active时代表当前项是选中页码

注意:disabled和active字段返回值前后带空格,判断状态时不要用全等匹配,用includes判断更可靠。

完整实现代码

以下是基于React Native Hooks的实现,同时支持下拉刷新、上拉自动加载下一页、手动点击页码跳转三种交互:

import { useState, useEffect, useCallback } from 'react';
import { 
  View, 
  Text, 
  FlatList, 
  TouchableOpacity, 
  ActivityIndicator,
  StyleSheet 
} from 'react-native';

export default function PaginatedList() {
  // 核心状态定义
  const [listData, setListData] = useState([]);
  const [pagination, setPagination] = useState(null);
  const [loading, setLoading] = useState(false);
  const [refreshing, setRefreshing] = useState(false);

  // 封装请求方法
  const fetchPageData = useCallback(async (targetPage, isRefresh = false) => {
    if (loading) return;
    isRefresh ? setRefreshing(true) : setLoading(true);
    
    try {
      // 替换为实际接口地址和请求参数
      const response = await fetch(`https://your-api-domain.com/list?page=${targetPage}`);
      const result = await response.json();
      
      // 替换为接口实际返回的列表字段名
      const newPageList = result.list;
      setPagination(result.Pagination);
      setListData(prev => isRefresh ? newPageList : [...prev, ...newPageList]);
    } catch (error) {
      console.log('列表请求异常', error);
    } finally {
      setLoading(false);
      setRefreshing(false);
    }
  }, [loading]);

  // 页面初始化加载第一页
  useEffect(() => {
    fetchPageData(1, true);
  }, []);

  // 下拉刷新逻辑
  const handleRefresh = useCallback(() => {
    fetchPageData(1, true);
  }, [fetchPageData]);

  // 上拉加载下一页逻辑
  const nextPageConfig = pagination?.data?.find(item => item.name === 'NEXT');
  const canLoadNext = nextPageConfig?.onclick === 1 && !nextPageConfig?.disabled?.includes('disabled');
  const handleEndReached = () => {
    if (canLoadNext && !loading) {
      fetchPageData(Number(nextPageConfig.value));
    }
  };

  // 底部页码栏渲染
  const renderPaginationBar = () => {
    if (!pagination) return null;
    return (
      <View style={styles.paginationWrap}>
        <Text style={styles.showingText}>{pagination.showing}</Text>
        <View style={styles.btnGroup}>
          {pagination.data.map((btnItem, index) => {
            const isDisabled = btnItem.disabled?.includes('disabled');
            const isActive = btnItem.active?.includes('active');
            return (
              <TouchableOpacity
                key={index}
                disabled={isDisabled}
                onPress={() => fetchPageData(Number(btnItem.value), true)}
                style={[
                  styles.pageBtn,
                  isActive && styles.activeBtn,
                  isDisabled && styles.disabledBtn
                ]}
              >
                <Text style={[styles.btnText, isActive && styles.activeBtnText]}>
                  {btnItem.name}
                </Text>
              </TouchableOpacity>
            )
          })}
        </View>
      </View>
    )
  };

  // 列表项渲染,替换为实际业务组件
  const renderListItem = ({ item }) => {
    return (
      <View style={styles.listItem}>
        <Text>{item.title}</Text>
      </View>
    )
  };

  return (
    <View style={styles.pageWrap}>
      <FlatList
        data={listData}
        keyExtractor={(item, index) => String(item.id || index)}
        renderItem={renderListItem}
        refreshing={refreshing}
        onRefresh={handleRefresh}
        onEndReached={handleEndReached}
        onEndReachedThreshold={0.2}
        ListFooterComponent={() => {
          return loading 
            ? <ActivityIndicator style={styles.loadingTip} /> 
            : renderPaginationBar()
        }}
      />
    </View>
  )
}

const styles = StyleSheet.create({
  pageWrap: {
    flex: 1,
    backgroundColor: '#fff'
  },
  listItem: {
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#f0f0f0'
  },
  loadingTip: {
    padding: 16
  },
  paginationWrap: {
    padding: 16,
    gap: 12
  },
  showingText: {
    textAlign: 'center',
    color: '#666'
  },
  btnGroup: {
    flexDirection: 'row',
    justifyContent: 'center',
    gap: 8,
    flexWrap: 'wrap'
  },
  pageBtn: {
    paddingHorizontal: 12,
    paddingVertical: 6,
    backgroundColor: '#f5f5f5',
    borderRadius: 4
  },
  activeBtn: {
    backgroundColor: '#2196F3'
  },
  disabledBtn: {
    opacity: 0.4
  },
  btnText: {
    color: '#333',
    fontSize: 14
  },
  activeBtnText: {
    color: '#fff'
  }
})

关键逻辑说明

  • 加了loading状态锁,避免滚动时重复触发接口请求
  • 所有状态判断用includes匹配,兼容接口返回字段前后带空格的问题
  • 页码的value字段统一转数字再传参,规避字符串类型导致的参数异常
  • 如果不需要手动点击页码的交互,可以直接去掉页码栏渲染逻辑,只保留上拉加载、下拉刷新即可,不需要处理中间页码的逻辑

内容的提问来源于stack exchange,提问作者075_Jenil Jariwala

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 08:33:11