React Native(Expo)点击TouchableOpacity修改边框样式的实现方案
解决React Native FlatList点击项切换边框颜色问题
你的代码里有几个关键问题导致点击后边框颜色不切换,下面是修正后的代码和问题说明:
问题点及修正:
- FlatList的extraData传错:
extraData需要传入要监听的状态值selectedStuId,而不是状态更新函数setSelectedStuId,这样状态变化时FlatList才会重新渲染。 - 初始选中ID不合理:
selectedStuId初始设为1,如果没有ID为1的学生,默认就会有错误的选中状态,改为null让所有项默认未选中。 - 样式判断用错变量:判断条件里写成了
item.stu_id === setSelectedStuId,应该用状态值selectedStuId。 - 缺少ToastAndroid导入:调用
ToastAndroid但没导入,需要添加到import里。 - API请求未监听参数变化:第二个
useEffect依赖数组为空,当course或div变化时不会重新请求数据,要把course和div加入依赖数组。 - 异步状态更新的日志问题:
setSelectedStuId是异步操作,之后立刻console.log(selectedStuId)会打印旧值,这是React正常机制,要查看更新后的值可以用useEffect监听selectedStuId变化。
修正后的完整代码:
import { View, Text, TouchableOpacity, SafeAreaView, FlatList, ToastAndroid } from 'react-native' import React, { useEffect, useState } from 'react' import { useNavigation, useLocalSearchParams } from 'expo-router' import { StyleSheet } from 'react-native'; import {Colors} from '../../../constants/Colors' export default function index() { const navigation = useNavigation(); const { course, div } = useLocalSearchParams() console.log({course, div}) const [data, setData] = useState(null); const [selectedStuId, setSelectedStuId] = useState(null); // 初始设为null const changeSelectedStudent = (id) => { setSelectedStuId(id); // 要查看更新后的值,用useEffect监听,这里直接打印是旧值 }; useEffect(() => { navigation.setOptions({ headerShown: false }) }, []) useEffect(() => { const getUserAuthentication = async () => { try { if(!course || !div) { // 只要一个参数为空就提示错误 ToastAndroid.show('Something went wrong', ToastAndroid.BOTTOM); return; } const response = await fetch( 'https://www.mywebsite.com/fetchStudentListAPI.php', { method:'POST', headers: { Accept: 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ firstParam: course, secondParam: div }), } ); const json = await response.json(); setData(json); console.log(json[0]?.stu_name); // 加可选链避免数组为空报错 } catch (error) { console.error(error); } }; getUserAuthentication(); }, [course, div]) // 添加依赖,参数变化时重新请求 // 监听选中ID变化,查看更新后的值 useEffect(() => { console.log('当前选中的学生ID:', selectedStuId); }, [selectedStuId]) return ( <View style={{ padding:25, paddingTop:50, backgroundColor:Colors.WHITE, height:'100%' }}> <Text style={{ fontFamily:'Poppins-Bold', fontSize:30, textAlign:'center' }}>Take Attendance</Text> <Text style={{ fontFamily:'Poppins-Bold', fontSize:18, textAlign:'center' }}>Course: {course} Div: {div}</Text> <SafeAreaView style={styles.container}> <FlatList data={data} extraData={selectedStuId} // 改为监听状态值 renderItem={({ item }) => ( <TouchableOpacity onPress={() => changeSelectedStudent(item.stu_id)}> <Text style={ item.stu_id === selectedStuId // 改为用状态值判断 ? styles.selectedItem // 重命名样式更清晰 : styles.unselectedItem }> {item.stu_roll_no} {item.stu_name} </Text> </TouchableOpacity> )} keyExtractor={(item) => item.stu_id} /> </SafeAreaView> <TouchableOpacity style={{ padding:20, backgroundColor:Colors.PRIMARY, borderRadius:15, marginTop:50 }}> <Text style={{ color:Colors.WHITE, textAlign:'center', fontFamily:'Poppins' }}> Submit </Text> </TouchableOpacity> </View> ) } const styles = StyleSheet.create({ container: { padding: 50, flex: 1, }, unselectedItem: { // 未选中样式,红色边框 padding: 20, fontSize: 15, marginTop: 5, borderWidth:1, borderRadius:15, borderColor:Colors.RED, fontFamily:'Poppins', }, selectedItem: { // 选中样式,绿色边框 padding: 20, fontSize: 15, marginTop: 5, borderWidth:1, borderRadius:15, borderColor:Colors.GREEN, fontFamily:'Poppins', }, });
额外优化说明:
- 把样式名改成
unselectedItem和selectedItem,逻辑更直观,避免混淆。 - API请求里的判断从
!course && !div改成!course || !div,只要有一个参数为空就提示错误,更合理。 - 打印学生名字时加了可选链
json[0]?.stu_name,避免返回数据为空时报错。
内容的提问来源于stack exchange,提问作者Manoj
相关产品推荐
相关产品推荐

