React Native 中@react-native-community/checkbox 勾选正常但取消失效
复选框取消勾选无响应的问题排查与修复
核心问题定位
- 违反React状态不可变更新规则
原changeCheckboxValue函数中,const data = services是直接获取原state的引用,和原始状态指向同一块内存地址。直接修改数组内对象的属性后,将同一个引用传入setServices时,React的浅比较逻辑无法识别到状态变更,不会触发组件重渲染,最终表现为后续操作(比如取消勾选)没有视觉反馈。 - 事件重复触发冲突
外层TouchableOpacity的onPress和CheckBox自身的onValueChange绑定了同一个更新函数,单次点击会触发两次状态修改,导致状态来回切换、抵消更新效果。 - 列表渲染未添加唯一key值
原services.map渲染列表时,没有给外层View绑定key属性,React做列表diff时会出现组件状态复用的异常,进一步加剧勾选状态不更新的问题。 - 代码语法隐患
useEffect的回调是普通同步函数,却在内部直接使用await获取AsyncStorage中的token,会触发语法错误,实际运行时无法正确携带请求头。 - 字段拼写不匹配
接口返回的字段是isCheked(拼写缺失字母c),但代码中读取的是isChecked,导致初始勾选状态永远为undefined,不符合预期。
修复方案
- 更新状态时通过展开运算符生成全新的数组和对象引用,保证React能检测到状态变化
- 移除重复的事件绑定,仅保留单一路径的状态更新触发逻辑
- 在
useEffect内部声明异步函数,正确处理token的异步获取逻辑 - 统一字段拼写,适配接口返回的字段格式
- 列表渲染时给每个项绑定唯一key,符合React渲染规范
修复后代码
import React, {useState, useEffect} from 'react'; import {Text, View, TouchableOpacity} from 'react-native'; import CheckBox from '@react-native-community/checkbox'; import {apiUrl} from '../../utilities/index'; import AsyncStorage from '@react-native-async-storage/async-storage'; import axios from 'axios'; const BookingCreate = ({route, navigation}) => { const [services, setServices] = useState([]); useEffect(() => { // 内部声明异步函数处理请求逻辑 const fetchServices = async () => { try { const token = await AsyncStorage.getItem('token'); const res = await axios.get(apiUrl + `salonService/salonID/${route.params.salonId}`, { headers: { auth: token, 'Content-Type': 'application/json', }, }) // 适配接口字段拼写,将isCheked映射为代码内统一使用的isChecked const serviceList = res.data.servicesList.map(item => ({ ...item, isChecked: item.isCheked ?? false })) setServices(serviceList); } catch (e) { alert(e); } } fetchServices() }, [route.params.salonId]); const changeCheckboxValue = (id) => { // 生成全新数组,而非直接引用原state setServices(prevServices => prevServices.map(item => { // 匹配到目标项时生成全新对象,翻转isChecked状态 if (item._id === id) { return { ...item, isChecked: !item.isChecked } } // 非目标项保留原对象引用 return item }) ) }; return ( <View style={{flex: 1}}> {services.length != 0 ? ( services.map((item) => ( <View key={item._id}> <TouchableOpacity style={{flexDirection: 'row', alignItems: 'center'}} onPress={() => changeCheckboxValue(item._id)}> <CheckBox value={item.isChecked} onAnimationType="fill" offAnimationType="fade" boxType="square" /> <Text style={{marginLeft: 10}}>{item.serviceId.name}</Text> <Text style={{marginLeft: 10}}>{item.category}</Text> <Text style={{marginLeft: 10}}>{item.price}</Text> </TouchableOpacity> </View> )) ) : ( <Text>Loading</Text> )} </View> ) } export default BookingCreate;
注意:CheckBox为受控组件,必须确保传入的
value值来自最新的state值,不能通过直接修改原数组对象属性的方式更新状态。
内容的提问来源于stack exchange,提问作者sigmato
相关产品推荐
相关产品推荐

