如何在React Native中实现API数据与SectionList的集成
如何在React Native的SectionList中集成API数据
步骤1:获取API数据
用React的useState保存原始数据、加载状态和错误信息,通过useEffect发起网络请求获取API数据:
import { useState, useEffect } from 'react'; import { View, SectionList, Text, ActivityIndicator } from 'react-native'; import RowComponent from './RowComponent'; // 导入你的自定义行组件 const TransactionList = () => { const [rawData, setRawData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchTransactions = async () => { try { const response = await fetch('你的API接口地址'); if (!response.ok) throw new Error('请求失败'); const data = await response.json(); setRawData(data); } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchTransactions(); }, []); // 后续逻辑写在此处 };
步骤2:转换API数据为SectionList所需格式
需要将API返回的扁平数据按日期分组(今日、昨日、历史日期),并映射为SectionList要求的结构:
// 辅助函数:判断交易日期所属分组 const getDateGroup = (dateString) => { const today = new Date(); const transactionDate = new Date(dateString); // 重置时间部分,仅比较日期 const normalizeDate = (date) => { const d = new Date(date); d.setHours(0, 0, 0, 0); return d; }; const normalizedToday = normalizeDate(today); const normalizedTransactionDate = normalizeDate(transactionDate); const oneDay = 24 * 60 * 60 * 1000; if (normalizedTransactionDate.getTime() === normalizedToday.getTime()) { return { title: 'Today', key: 'today' }; } else if (normalizedTransactionDate.getTime() === normalizedToday.getTime() - oneDay) { return { title: 'Yesterday', key: 'yesterday' }; } else { // 格式化历史日期为「DD MMM YYYY」格式 const formattedDate = transactionDate.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }).toUpperCase(); return { title: formattedDate, key: formattedDate.toLowerCase() }; } }; // 核心转换函数:将API数据转为SectionList结构 const transformApiData = (data) => { // 按日期分组 const grouped = data.reduce((acc, item) => { const { title: groupTitle, key: groupKey } = getDateGroup(item.createdAt); if (!acc[groupKey]) { acc[groupKey] = { title: groupTitle, key: groupKey, data: [] }; } // 映射API字段到RowComponent所需结构 acc[groupKey].data.push({ id: item.id, // 用于唯一key iconUrl: '', // 可根据transactionType/status设置对应图标地址 primaryKey: item.title || item.transactionType, // 主标题 primaryLabel: item.quantity, // 交易数量 secondaryKey: new Date(item.createdAt).toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }), // 交易时间 secondaryLabel: item.token // 代币类型 }); return acc; }, {}); // 排序分组:今日→昨日→历史日期从新到旧 return Object.values(grouped).sort((a, b) => { if (a.key === 'today') return -1; if (b.key === 'today') return 1; if (a.key === 'yesterday') return -1; if (b.key === 'yesterday') return 1; return new Date(b.title) - new Date(a.title); }); }; // 在组件中生成SectionList所需的sections const sections = transformApiData(rawData);
步骤3:调整SectionList渲染逻辑
替换静态数据为转换后的sections,并使用API返回的id作为唯一key:
const handleRenderSectionItem = ({ item }) => { const { iconUrl, primaryKey, primaryLabel, secondaryKey, secondaryLabel } = item; return ( <RowComponent onPress={() => { /* 可添加点击跳转逻辑 */ }} iconUri={iconUrl} primaryKey={primaryKey} primaryLabel={primaryLabel} secondaryKey={secondaryKey} secondaryLabel={secondaryLabel} /> ); }; const handleRenderSectionHeader = ({ section: { title }}) => ( <Text style={{ marginVertical: 15, fontSize: 16, fontWeight: '600' }}> {title} </Text> ); // 加载/错误状态处理 if (loading) return <ActivityIndicator size="large" color="#000" style={{ flex: 1, justifyContent: 'center' }} />; if (error) return <Text style={{ flex: 1, textAlign: 'center', padding: 20 }}>加载失败:{error}</Text>; // 最终渲染 return ( <View style={{ flex: 1, paddingHorizontal: 12 }}> <SectionList sections={sections} keyExtractor={(item) => item.id.toString()} renderItem={handleRenderSectionItem} renderSectionHeader={handleRenderSectionHeader} stickySectionHeadersEnabled={false} contentContainerStyle={{ paddingVertical: 10 }} /> </View> );
完整组件代码
整合所有逻辑后的完整实现:
import { useState, useEffect } from 'react'; import { View, SectionList, Text, ActivityIndicator } from 'react-native'; import RowComponent from './RowComponent'; const TransactionList = () => { const [rawData, setRawData] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchTransactions = async () => { try { const response = await fetch('你的API接口地址'); if (!response.ok) throw new Error('请求失败'); const data = await response.json(); setRawData(data); } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchTransactions(); }, []); const getDateGroup = (dateString) => { const today = new Date(); const transactionDate = new Date(dateString); const normalizeDate = (date) => { const d = new Date(date); d.setHours(0, 0, 0, 0); return d; }; const normalizedToday = normalizeDate(today); const normalizedTransactionDate = normalizeDate(transactionDate); const oneDay = 24 * 60 * 60 * 1000; if (normalizedTransactionDate.getTime() === normalizedToday.getTime()) { return { title: 'Today', key: 'today' }; } else if (normalizedTransactionDate.getTime() === normalizedToday.getTime() - oneDay) { return { title: 'Yesterday', key: 'yesterday' }; } else { const formattedDate = transactionDate.toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }).toUpperCase(); return { title: formattedDate, key: formattedDate.toLowerCase() }; } }; const transformApiData = (data) => { const grouped = data.reduce((acc, item) => { const { title: groupTitle, key: groupKey } = getDateGroup(item.createdAt); if (!acc[groupKey]) { acc[groupKey] = { title: groupTitle, key: groupKey, data: [] }; } acc[groupKey].data.push({ id: item.id, iconUrl: '', primaryKey: item.title || item.transactionType, primaryLabel: item.quantity, secondaryKey: new Date(item.createdAt).toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' }), secondaryLabel: item.token }); return acc; }, {}); return Object.values(grouped).sort((a, b) => { if (a.key === 'today') return -1; if (b.key === 'today') return 1; if (a.key === 'yesterday') return -1; if (b.key === 'yesterday') return 1; return new Date(b.title) - new Date(a.title); }); }; const sections = transformApiData(rawData); const handleRenderSectionItem = ({ item }) => { const { iconUrl, primaryKey, primaryLabel, secondaryKey, secondaryLabel } = item; return ( <RowComponent onPress={() => {}} iconUri={iconUrl} primaryKey={primaryKey} primaryLabel={primaryLabel} secondaryKey={secondaryKey} secondaryLabel={secondaryLabel} /> ); }; const handleRenderSectionHeader = ({ section: { title }}) => ( <Text style={{ marginVertical: 15, fontSize: 16, fontWeight: '600' }}> {title} </Text> ); if (loading) return <ActivityIndicator size="large" color="#000" style={{ flex: 1, justifyContent: 'center' }} />; if (error) return <Text style={{ flex: 1, textAlign: 'center', padding: 20 }}>加载失败:{error}</Text>; return ( <View style={{ flex: 1, paddingHorizontal: 12 }}> <SectionList sections={sections} keyExtractor={(item) => item.id.toString()} renderItem={handleRenderSectionItem} renderSectionHeader={handleRenderSectionHeader} stickySectionHeadersEnabled={false} contentContainerStyle={{ paddingVertical: 10 }} /> </View> ); }; export default TransactionList;
内容的提问来源于stack exchange,提问作者Kumar Shivam
相关产品推荐
相关产品推荐

