如何在React Native函数式组件中渲染嵌套JSON数据到FlatList
如何在React Native函数式组件中渲染嵌套JSON到FlatList
你的代码无法正确渲染的核心问题是:FlatList的数据源用错了。RestaurantsData是一个仅包含单个对象的数组,这个对象里的BeveragesData和DesertsData才是真正存储餐厅数据的子数组,而你直接把外层数组传给了FlatList,导致每个item是那个包含两个子数组的大对象,根本没有id、title、Image这些属性,自然渲染失败。
下面给你几种可行的实现方案,根据你的需求选择:
方案一:合并所有分类的餐厅数据,渲染全部项
如果不需要区分分类,只想把所有餐厅项一次性渲染出来,可以先把嵌套的子数组合并成一个数组:
import React from "react"; import { Text, Image, TouchableOpacity, StyleSheet, View, FlatList } from 'react-native'; import RestaurantsData from '../screens/Data/data'; // 合并所有子数组:取出外层对象里的BeveragesData和DesertsData,合并成一个数组 const mergedData = [ ...RestaurantsData[0].BeveragesData, ...RestaurantsData[0].DesertsData ]; const Restaurant = (props) => { const renderItem = ({ item }) => { return ( <View style={styles.flatlist}> <Image source={item.Image} style={styles.flatlistimage} /> <TouchableOpacity> <Text style={{ fontSize: 20, color: 'black', fontWeight: 'bold' }}>{item.title}</Text> <Text style={{ fontSize: 16, color: '#666' }}>¥{item.price}</Text> </TouchableOpacity> </View> ) } return ( <View style={styles.container}> <FlatList data={mergedData} renderItem={renderItem} keyExtractor={item => item.id.toString()} // 注意id是数字,转成字符串避免警告 /> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, padding: 10 }, flatlist: { marginBottom: 15, borderRadius: 8, padding: 10, backgroundColor: '#fff', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3 }, flatlistimage: { width: '100%', height: 150, borderRadius: 8, marginBottom: 10 } }) export default Restaurant;
方案二:按分类分组渲染(使用SectionList)
如果需要保留分类标题(比如“饮品”、“甜品”),用SectionList比FlatList更合适,先把数据转换成SectionList需要的格式:
import React from "react"; import { Text, Image, TouchableOpacity, StyleSheet, View, SectionList } from 'react-native'; import RestaurantsData from '../screens/Data/data'; // 转换成SectionList需要的结构:[{title: 分类名, data: 对应数组}, ...] const sectionData = [ { title: '饮品', data: RestaurantsData[0].BeveragesData }, { title: '甜品', data: RestaurantsData[0].DesertsData } ]; const Restaurant = (props) => { const renderItem = ({ item }) => { return ( <View style={styles.itemContainer}> <Image source={item.Image} style={styles.itemImage} /> <TouchableOpacity> <Text style={styles.itemTitle}>{item.title}</Text> <Text style={styles.itemPrice}>¥{item.price}</Text> </TouchableOpacity> </View> ) } const renderSectionHeader = ({ section }) => { return ( <View style={styles.sectionHeader}> <Text style={styles.sectionTitle}>{section.title}</Text> </View> ) } return ( <View style={styles.container}> <SectionList sections={sectionData} renderItem={renderItem} renderSectionHeader={renderSectionHeader} keyExtractor={item => item.id.toString()} /> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, padding: 10 }, sectionHeader: { padding: 12, backgroundColor: '#f5f5f5', borderRadius: 8, marginBottom: 10 }, sectionTitle: { fontSize: 18, fontWeight: 'bold', color: '#333' }, itemContainer: { marginBottom: 10, borderRadius: 8, padding: 10, backgroundColor: '#fff', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3 }, itemImage: { width: '100%', height: 150, borderRadius: 8, marginBottom: 10 }, itemTitle: { fontSize: 20, color: 'black', fontWeight: 'bold' }, itemPrice: { fontSize: 16, color: '#666', marginTop: 5 } }) export default Restaurant;
方案三:嵌套FlatList(外层渲染分类,内层渲染分类项)
如果需要更灵活的布局(比如每个分类横向滚动),可以用嵌套FlatList:
import React from "react"; import { Text, Image, TouchableOpacity, StyleSheet, View, FlatList } from 'react-native'; import RestaurantsData from '../screens/Data/data'; // 提取分类列表,包含分类名和对应数据 const categoryList = [ { name: '饮品', data: RestaurantsData[0].BeveragesData }, { name: '甜品', data: RestaurantsData[0].DesertsData } ]; const Restaurant = (props) => { // 渲染每个分类的标题和内层FlatList const renderCategory = ({ item }) => { return ( <View style={styles.categoryContainer}> <Text style={styles.categoryTitle}>{item.name}</Text> <FlatList horizontal showsHorizontalScrollIndicator={false} data={item.data} keyExtractor={item => item.id.toString()} renderItem={({ item: restaurant }) => ( <View style={styles.restaurantItem}> <Image source={restaurant.Image} style={styles.restaurantImage} /> <TouchableOpacity> <Text style={styles.restaurantTitle}>{restaurant.title}</Text> <Text style={styles.restaurantPrice}>¥{restaurant.price}</Text> </TouchableOpacity> </View> )} /> </View> ) } return ( <View style={styles.container}> <FlatList data={categoryList} renderItem={renderCategory} keyExtractor={item => item.name} showsVerticalScrollIndicator={false} /> </View> ) } const styles = StyleSheet.create({ container: { flex: 1, padding: 10 }, categoryContainer: { marginBottom: 20 }, categoryTitle: { fontSize: 18, fontWeight: 'bold', color: '#333', marginBottom: 10, paddingLeft: 5 }, restaurantItem: { width: 180, marginRight: 10, borderRadius: 8, padding: 10, backgroundColor: '#fff', shadowColor: '#000', shadowOffset: { width: 0, height: 2 }, shadowOpacity: 0.1, shadowRadius: 4, elevation: 3 }, restaurantImage: { width: '100%', height: 120, borderRadius: 8, marginBottom: 8 }, restaurantTitle: { fontSize: 16, color: 'black', fontWeight: 'bold' }, restaurantPrice: { fontSize: 14, color: '#666', marginTop: 4 } }) export default Restaurant;
额外提示:
keyExtractor里要把数字类型的id转成字符串,避免React Native警告- 图片路径要确保正确,
require的路径是相对于当前组件文件的位置 - 如果需要根据路由参数传递的分类(比如
props.route.params指定要渲染哪个分类),可以直接取对应子数组作为数据源:
然后把const selectedCategory = props.route.params; // 假设传递的是'BeveragesData'或'DesertsData' const targetData = RestaurantsData[0][selectedCategory];targetData传给FlatList的data即可。
内容的提问来源于stack exchange,提问作者ReactNative
相关产品推荐
相关产品推荐

