React Native调用SQL Server后端API渲染列表报错排查
React Native 列表渲染报错修复方案
你遇到的 Text strings must be rendered within a <Text> component 报错和列表不渲染问题,由多个代码逻辑错误共同导致,接口返回数据参考如下:
核心错误点
- 函数组件和类组件写法混用:你使用了
useState/useEffect的函数组件写法,但代码里大量使用只有类组件才存在的this.setState、this.props、this.xxx调用,函数组件没有this实例,这些逻辑全部无效,状态根本无法正常更新。 - 列表组件API使用错误:旧版
ListView早已被官方废弃移除,替换为FlatList后你仍然套用ListView的DataSource/cloneWithRows逻辑,而FlatList不需要额外包装数据源,直接接收原始数组即可。 - 渲染参数传递错误:FlatList的
renderItem回调参数为包裹对象,真实行数据存在item字段下,你直接读取参数对象的job字段会拿到undefined;ItemSeparatorComponent需要传入组件引用,你直接执行组件函数传入返回值,会触发渲染异常。 - 请求配置错误:React Native环境没有浏览器的跨域限制,不需要加
no-cors参数;真机调试时localhost指向的是手机本身,无法访问你电脑上的本地服务。 - 未校验接口返回格式:如果你的PHP接口返回的是带状态码的包裹结构(比如
{code:200, data: 数组}),直接把整个响应当列表数组传入,FlatList遍历时会拿到非预期值,触发文本渲染报错。
修复后可直接运行的代码
import React, { useState, useEffect } from 'react'; import {View, Text, StyleSheet, ActivityIndicator, Platform, FlatList} from 'react-native'; import {useNavigation} from '@react-navigation/native'; import {StatusBar} from 'expo-status-bar'; export default function StopJob(){ const [isLoading, setIsLoading] = useState(true); // 直接存储接口返回的原始数组,不需要额外DataSource包装 const [listData, setListData] = useState([]); // 函数组件通过钩子获取navigation实例,不需要走this.props const navigation = useNavigation(); useEffect(()=>{ // 注意:真机调试替换为你电脑的局域网IP,安卓模拟器可使用10.0.2.2访问电脑本地服务 fetch('http://你的服务地址/api/findid.php') .then((response) => response.json()) .then((responseJson) => { setIsLoading(false); // 按接口实际结构调整取值,如果接口返回包裹结构就取对应数组字段,这里做了数组类型兜底 setListData(Array.isArray(responseJson) ? responseJson : []); }) .catch((error) => { console.error('接口请求异常:', error); setIsLoading(false); }) },[]); // 行点击跳转逻辑 const handleRowPress = (rowData) => { navigation.navigate('Third', { Userid : rowData.user, Job : rowData.job, JobId : rowData.jobid, MachineCode : rowData.machinecode, StartTime : rowData.startTime }); } // 列表分隔线组件 const ItemSeparator = () => { return ( <View style={{ height: .5, width: "100%", backgroundColor: "#000", }} /> ); } // 加载态渲染 if(isLoading){ return( <View style={{flex: 1, paddingTop: 20}}> <ActivityIndicator /> </View> ) } return( <View style={styles.mainContainer}> <FlatList data={listData} // 保证key唯一,如果jobid为唯一值可替换为item => String(item.jobid) keyExtractor={(item, index) => String(item.user || index)} ItemSeparatorComponent={ItemSeparator} renderItem={ ({item}) => ( <Text style={styles.rowText} onPress={() => handleRowPress(item)} > {item.job} </Text> )} /> </View> ); } const styles = StyleSheet.create({ mainContainer :{ flex:1, paddingTop: Platform.OS === 'ios' ? 20 : 0, marginLeft: 5, marginRight: 5 }, rowText: { fontSize: 20, paddingRight: 10, paddingTop: 10, paddingBottom: 10, } });
调试注意事项
- 代码跑通前先在fetch的then回调里打印
responseJson,确认接口返回的是纯数组还是带外层包裹的结构,如果是包裹结构要取到实际的列表数组再存入state。 - 本地调试时确保手机和电脑连接同一个WiFi,关闭电脑的公共网络防火墙,否则手机无法访问你电脑上启动的本地服务。
- 不要参考发布时间过早的React Native教程,2020年之后的RN版本已经彻底移除ListView,类组件的示例代码直接套用到函数组件中必然出现兼容性问题。
内容的提问来源于stack exchange,提问作者d.chan
相关产品推荐
相关产品推荐

