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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:18:37