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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 05:13:16