React Native从MySQL拉取用户数据时页面持续加载无数据
问题排查&修复方案
页面持续加载的核心原因是前后端代码存在多处语法、逻辑错误,请求流程跑不通,且错误分支没有更新加载状态,导致isLoading始终为true。
现存错误点
前端React Native端
- 组件写法混淆:写的是函数组件,却错误使用类组件的
this.setState、this.props、this.xxx.bind语法,函数组件不存在this实例,这些代码运行直接报错。 - 请求配置缺失:
fetch默认发GET请求,不会携带body参数,也没设置Content-Type请求头,后端拿不到JSON格式的传参。 - 参数字段名不匹配:前端传参字段写的是
Userid(首字母大写),后端取参字段是userid(全小写),后端拿不到用户ID。 - 路由参数取值错误:函数组件接收props的写法不对,拿不到路由传的userid。
- 组件使用过时:
ListView早已被React Native官方废弃,换成官方推荐的FlatList即可,不需要手动维护DataSource。 - 状态更新逻辑缺失:请求报错的catch分支没有把
isLoading设为false,请求失败时会一直卡在加载态。 - 本地访问地址错误:安卓模拟器访问电脑本地服务不能用
localhost,要换成10.0.2.2;真机测试要换成电脑的局域网IP,且设备和电脑连同一网络。
后端PHP端
- 响应格式不统一:查不到数据时直接返回纯文本
No Results Found.,前端用response.json()解析非JSON内容会直接抛错。 - 参数取值错误:前端如果传大写
Userid,后端取userid会拿到空值,拼出来的SQL直接语法错误。 - 响应输出逻辑错误:循环里反复覆盖
$json变量,最后没有输出JSON内容,前端拿不到返回数据。 - 存在SQL注入风险:直接拼接用户传入的参数到SQL语句,容易被注入攻击,且没有做参数非空校验。
修正后代码
React Native端代码
import React, { useState, useEffect } from 'react'; import {View,Text, StyleSheet, ActivityIndicator, Platform, FlatList} from 'react-native'; import {useNavigation, useRoute} from'@react-navigation/native'; import {StatusBar} from'expo-status-bar'; export default function StopJob(){ const navigation = useNavigation(); const route = useRoute(); const[isLoading,setIsLoading]=useState(true); const [listData, setListData] = useState([]); // 取路由传入的userid const userid = route.params?.userid; useEffect(()=>{ // 没拿到userid直接结束加载 if(!userid) { setIsLoading(false); return; } const requestData = { userid: userid, // 字段名和后端保持一致,全小写 } // 注意:安卓模拟器本地调试把localhost换成10.0.2.2,真机换电脑局域网IP fetch('http://10.0.2.2/api/findid.php',{ method: 'POST', headers: { 'Content-Type': 'application/json', }, body:JSON.stringify(requestData) }) .then((response) => response.json()) .then((responseJson) => { setListData(responseJson); setIsLoading(false); }) .catch((error) => { console.error(error); setIsLoading(false); // 报错也要关闭加载态 }) },[userid]); // 列表项点击跳转 const handleItemPress = (rowData) => { navigation.navigate('Third', { Userid : rowData.user, Job : rowData.job, JobId : rowData.jobid, MachineCode : rowData.machinecode, StartTime : rowData.startTime }); } // 列表分割线 const renderSeparator = () => { 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_For_Show_StudentList_Activity}> <FlatList data={listData} ItemSeparatorComponent={renderSeparator} keyExtractor={(item, index) => index.toString()} renderItem={({item}) => ( <Text style={styles.rowViewContainer} onPress={() => handleItemPress(item)} > {item.job} </Text> )} /> </View> ); } const styles = StyleSheet.create({ MainContainer_For_Show_StudentList_Activity :{ flex:1, paddingTop: (Platform.OS == 'ios') ? 20 : 0, marginLeft: 5, marginRight: 5 }, rowViewContainer: { fontSize: 20, paddingRight: 10, paddingTop: 10, paddingBottom: 10, } });
PHP后端代码
<?php include 'config1.php'; // 统一设置响应头为JSON header('Content-Type: application/json'); $CN = new mysqli($HostName, $HostUser, $HostPass, $DatabaseName); // 连接错误处理 if ($CN->connect_error) { echo json_encode([]); exit; } $EncodedData = file_get_contents('php://input'); $DecodedData = json_decode($EncodedData, true); $userid = isset($DecodedData['userid']) ? trim($DecodedData['userid']) : ''; // 参数为空直接返回空数组 if(empty($userid)){ echo json_encode([]); exit; } // 用预处理语句防SQL注入 $stmt = $CN->prepare("SELECT * FROM scan where user = ?"); $stmt->bind_param("s", $userid); $stmt->execute(); $result = $stmt->get_result(); $data = []; if ($result->num_rows > 0) { while($row = $result->fetch_assoc()) { $data[] = $row; } } // 不管有没有数据都返回JSON格式数组 echo json_encode($data); $stmt->close(); $CN->close(); ?>
内容的提问来源于stack exchange,提问作者Dani
相关产品推荐
相关产品推荐

