React Native中Axios获取后端数据无法渲染至前端问题排查
React Native中Axios获取数据后无法渲染UI的问题
在React Native项目中使用Axios从后端获取数据,通过console.log能看到数据库返回的数据,但无法渲染到前端UI上,相关代码及问题如下:
相关代码
Axios实例
import axios from 'axios'; const instance = axios.create({ baseURL: 'http://localhost:8000/', responseType: 'json', withCredentials: true, }); export default instance;
ProductScreen组件
import React, {useEffect, useState} from 'react'; import {View} from 'react-native'; import MenuProduct from '../components/Product/MenuProduct'; import MainHeader from '../components/Header/MainHeader'; import {POPULAR, Top_Sell} from '../data'; import ProductItem from '../components/Product/ProductItem'; import instance from '../routes/instance'; const ProductScreen = () => { const [product, setProduct] = useState([]); useEffect(() => { const fetchData = async () => { const data = await instance('/api/products', { method: 'GET', }); setProduct(data); }; fetchData(); }, []); return ( <View style={{flex: 1}}> <MainHeader /> <MenuProduct list={Top_Sell} /> <ProductItem list={product} /> </View> ); }; export default ProductScreen;
ProductCard组件
import React from 'react'; import {Image, ScrollView, Text, TouchableOpacity, View} from 'react-native'; import {colors, sizes, spacing} from '../../constants/theme'; import AddItem from '../../utils/AddItem'; const CardHeight = 220; const ProductCard = ({props}) => { return ( <ScrollView> return ( <View style={{ marginLeft: spacing.l, marginBottom: spacing.l, marginRight: spacing.l, }}> <View> <View style={{ backgroundColor: colors.white, borderRadius: sizes.radius, shadowColor: colors.black, shadowRadius: 4, shadowOpacity: 0.1, shadowOffset: {width: 0, height: 2}, }}> <TouchableOpacity style={{ borderRadius: sizes.radius, overflow: 'hidden', flexDirection: 'row', }}> <Image style={{ borderRadius: sizes.radius, width: 160, height: CardHeight - 60, resizeMode: 'cover', }} source={props.image} /> <View style={{marginTop: spacing.l}}> <View style={{marginLeft: spacing.l, marginBottom: spacing.s}}> <Text style={{fontSize: 16, color: '#FA4A0C'}}> {props.title} </Text> </View> <View style={{marginLeft: spacing.l}}> <Text style={{fontSize: 14, color: '#8b8989'}}> {props.price} </Text> </View> <TouchableOpacity style={{marginLeft: 130}}> <AddItem /> </TouchableOpacity> </View> </TouchableOpacity> </View> </View> </View> ); }) </ScrollView> ); }; export default ProductCard;
ProductItem组件
import React from 'react'; import ProductCard from './ProductCard'; const ProductItem = ({list}) => { return ( <> {list.length > 0 && list.map((item, index) => { return ( <ProductCard id={item._id} image={item.image} title={item.title} price={item.price} item={item} key={index} /> ); })} </> ); }; export default ProductItem;
问题排查与修复方案
1. Axios请求数据处理错误
Axios发起请求后返回的是响应对象,后端返回的实际数据在该对象的data属性中。原代码直接将整个响应对象赋值给product状态,导致后续组件无法正确遍历数据。
修复后的fetchData函数:
const fetchData = async () => { try { const response = await instance('/api/products', { method: 'GET', }); // 提取响应对象中的实际数据 setProduct(response.data); } catch (error) { console.error('数据请求失败:', error); } };
2. ProductCard组件语法与props接收错误
- 组件内部存在多余的
return语句和语法错误(多余的); })),导致组件无法正常渲染。 - 组件定义时错误使用
{props}接收参数,实际需要直接解构传入的image、title等属性。 - React Native中网络图片的
source属性必须使用{uri: 图片地址}格式,不能直接传入字符串。
修复后的ProductCard组件:
import React from 'react'; import {Image, Text, TouchableOpacity, View} from 'react-native'; import {colors, sizes, spacing} from '../../constants/theme'; import AddItem from '../../utils/AddItem'; const CardHeight = 220; // 直接解构传入的属性 const ProductCard = ({image, title, price}) => { return ( <View style={{ marginLeft: spacing.l, marginBottom: spacing.l, marginRight: spacing.l, }}> <View style={{ backgroundColor: colors.white, borderRadius: sizes.radius, shadowColor: colors.black, shadowRadius: 4, shadowOpacity: 0.1, shadowOffset: {width: 0, height: 2}, }}> <TouchableOpacity style={{ borderRadius: sizes.radius, overflow: 'hidden', flexDirection: 'row', }}> {/* 网络图片使用uri格式 */} <Image style={{ borderRadius: sizes.radius, width: 160, height: CardHeight - 60, resizeMode: 'cover', }} source={{uri: image}} /> <View style={{marginTop: spacing.l}}> <View style={{marginLeft: spacing.l, marginBottom: spacing.s}}> <Text style={{fontSize: 16, color: '#FA4A0C'}}> {title} </Text> </View> <View style={{marginLeft: spacing.l}}> <Text style={{fontSize: 14, color: '#8b8989'}}> {price} </Text> </View> <TouchableOpacity style={{marginLeft: 130}}> <AddItem /> </TouchableOpacity> </View> </TouchableOpacity> </View> </View> ); }; export default ProductCard;
3. 额外优化建议
- 避免使用数组索引作为
key,改用后端返回的_id作为唯一标识:
// ProductItem组件中map部分修改 list.map((item) => { return ( <ProductCard id={item._id} image={item.image} title={item.title} price={item.price} item={item} key={item._id} // 使用唯一ID作为key /> ); })
内容的提问来源于stack exchange,提问作者hellosdfsf
相关产品推荐
相关产品推荐

