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

React Native中如何调用自定义Hook内的loadMoreItem实现FlatList分页

解决React Native FlatList分页调用自定义Hook方法的问题

问题根源

你的代码存在几个关键问题导致无法调用loadMoreItem:

  1. 自定义Hook useFetchData 仅返回了data状态,没有对外暴露loadMoreItem方法,子组件无法获取到该方法
  2. getContactsData方法存在逻辑错误(未定义的json变量、数据合并逻辑错误)
  3. 未监听pageNo的变化来触发新数据加载
  4. FlatList的keyExtractor使用错误,且未传入loadMoreItem方法

步骤1:修复useFetchData.js

修改Hook,暴露需要的方法并修复数据加载逻辑:

import { useEffect, useState } from 'react';
import { Alert } from 'react-native';
import axios from 'axios';

const useFetchData = (url) => {
  const [data, setData] = useState([]);
  const [pageNo, setPageNo] = useState(1);
  // 可选:添加加载状态避免重复请求
  const [isLoading, setIsLoading] = useState(false);

  // 初始数据加载
  const getDataUsingFetch = async () => {
    try {
      setIsLoading(true);
      const res = await fetch(url);
      if (!res.ok) throw Error('无法获取初始数据');
      const json = await res.json();
      setData(json);
    } catch (error) {
      console.error(error);
      alert(error.message);
    } finally {
      setIsLoading(false);
    }
  };

  // 加载更多数据的方法
  const loadMoreItem = () => {
    if (isLoading) return;
    setPageNo(prev => prev + 1);
  };

  // 分页数据加载(修复逻辑错误)
  const getContactsData = async () => {
    try {
      setIsLoading(true);
      const res = await fetch(`https://randomuser.me/api/?page=${pageNo}&results=10`);
      if (!res.ok) throw Error('无法加载更多数据');
      const responseData = await res.json();
      // 合并现有数据和新结果,使用函数式更新确保拿到最新state
      setData(prevData => [...prevData, ...responseData.results]);
    } catch (error) {
      console.error(error);
      alert(error.message);
    } finally {
      setIsLoading(false);
    }
  };

  // 监听pageNo变化,触发分页加载
  useEffect(() => {
    if (pageNo > 1) {
      getContactsData();
    }
  }, [pageNo]);

  // 初始加载数据
  useEffect(() => {
    getDataUsingFetch();
  }, [url]);

  // 返回需要的状态和方法
  return { data, loadMoreItem, isLoading };
};

export default useFetchData;

步骤2:修复dataList.js

修改组件,接收loadMoreItem和isLoading作为props,并正确配置FlatList:

import { StyleSheet, Text, FlatList, ActivityIndicator } from 'react-native';
import React from 'react';

const DataList = ({ data, loadMoreItem, isLoading }) => {
  return (
    <FlatList
      data={data}
      // 正确的keyExtractor:基于item的唯一属性生成key
      keyExtractor={(item) => item.id?.toString() || Math.random().toString()}
      onEndReached={loadMoreItem}
      onEndReachedThreshold={0.5}
      // 底部加载指示器(可选)
      ListFooterComponent={() => isLoading && <ActivityIndicator size="large" />}
      renderItem={({ item }) => (
        <Text style={styles.itemText}>
          任务:{item.title || item.name?.first} | 状态:{JSON.stringify(item.completed || false)}
        </Text>
      )}
    />
  );
};

const styles = StyleSheet.create({
  itemText: {
    padding: 16,
    borderBottomWidth: 1,
    borderBottomColor: '#eee'
  }
});

export default DataList;

步骤3:在父组件中使用

在页面组件中调用Hook,传递props给DataList:

import React from 'react';
import { View, StyleSheet } from 'react-native';
import useFetchData from './useFetchData';
import DataList from './dataList';

const HomeScreen = () => {
  // 传入初始加载的接口地址
  const { data, loadMoreItem, isLoading } = useFetchData('https://jsonplaceholder.typicode.com/todos');

  return (
    <View style={styles.container}>
      <DataList data={data} loadMoreItem={loadMoreItem} isLoading={isLoading} />
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 20
  }
});

export default HomeScreen;

关键说明

  • Hook暴露方法:必须把loadMoreItem从Hook中返回,才能在子组件中调用
  • 数据合并逻辑:使用setData(prev => [...prev, newData])确保合并的是最新的状态
  • 避免重复请求:添加isLoading状态,防止快速滚动时多次触发加载
  • keyExtractor正确性:必须基于item的唯一属性生成key,不能直接使用data.id

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:45:37