React Native中如何实现复选框控制数组筛选与状态更新?
React Native复选框筛选状态同步问题修复
问题描述
开发包含多复选框的Modal筛选功能时,勾选复选框可将对应值存入checkedValues数组并通过setNewArray更新状态,FlatList基于该状态展示数据。但取消勾选时,无法从checkedValues数组移除对应值,无论勾选/取消操作,值都会被添加到数组中。
错误原因分析
- 全局变量误用:使用全局变量
checkedValues而非React状态,变量变化无法触发组件重新渲染,状态更新不同步。 - 逻辑局限性:最初的
filtered函数仅判断isChecked.created的状态,未处理其他复选框类型,且无论条件是否满足,都会执行checkedValues.push(type),导致值始终被添加。 - 状态类型错误:
new_Array的状态类型声明为string,实际应定义为数组类型。
修复方案
- 将
checkedValues改为React状态变量,确保变化能触发组件更新。 - 重构
filtered函数:根据当前类型是否已存在于checkedValues中,决定执行添加或移除操作,再重新筛选数据更新new_Array。 - 修正
new_Array的状态类型为数组。 - 优化“Clear”按钮逻辑,同步重置所有状态。
修正后的完整代码
import React, {useState, useEffect} from 'react'; import { View, Text, Image, StyleSheet, TextInput, TouchableOpacity, TouchableWithoutFeedback, FlatList } from 'react-native'; import {Search} from 'react-native-feather'; import SearchItem from './src/Screens/SearchItem'; import {getHeight, getWidth} from './src/Components/CommonFunctions'; import CheckBox from '@react-native-community/checkbox'; import Modal from 'react-native-modal'; import { widthPercentageToDP as wp, heightPercentageToDP as hp, } from 'react-native-responsive-screen'; const FullfillmentScreen = ({route}) => { const {data} = route.params; const [currentDate, setCurrentDate] = useState<string>(''); useEffect(() => { const date = new Date().getDate(); const month = new Date().getMonth() + 1; const year = new Date().getFullYear(); const hour = new Date().getHours(); const min = new Date().getMinutes(); setCurrentDate(`${date} ${month} ${year}, ${hour}:${min}`); }, []); const array: any = [ { id: '1', state: 'Created', date: 'Over Due', packageNumber: 'PKGX-128788868-17HJGJG', name: 'muqsit Chowhan', delivery: 'Next Day', val: 'VAS', }, { id: '2', state: 'Created', date: [currentDate], packageNumber: 'PKGX-128788868-17HJGJG', name: 'Ali', delivery: 'Next Day', val: 'VAS', }, { id: '3', state: 'Processing', date: [currentDate], packageNumber: 'PKGX-128788868-17HJGJG', name: 'Chowhan', delivery: 'Next Day', val: 'VAS', }, { id: '4', state: 'Picked', date: [currentDate], packageNumber: 'PKGX-128788868-17HJGJG', name: 'Jamie', delivery: 'Next Day', val: 'VAS', }, { id: '5', state: 'Packed', date: [currentDate], packageNumber: 'PKGX-128788868-17HJGJG', name: 'qasim', delivery: 'Next Day', val: 'VAS', }, { id: '6', state: 'Created', date: [currentDate], packageNumber: 'PKGX-128788868-17HJGJG', name: 'abdullah', delivery: 'Next Day', val: 'VAS', }, { id: '7', state: 'Created', date: [currentDate], packageNumber: 'PKGX-128788868-17HJGJG', name: 'kamran', delivery: 'Next Day', val: 'VAS', }, { id: '8', state: 'Created', date: [currentDate], packageNumber: 'PKGX-128788868-17HJGJG', name: 'hamza', delivery: 'Next Day', val: 'VAS', }, ]; const [search, setSearch] = useState(''); const [apply, setApply] = useState<boolean>(false); const [modalVisibile, setModalVisibile] = useState<boolean>(false); // 修正new_Array的类型为数组 const [new_Array, setNewArray] = useState<any[]>([]); const [isChecked, setIsChecked] = useState<any>({ created: false, processing: false, picked: false, packed: false, completed: false, cancelled: false, }); // 将checkedValues改为状态变量 const [checkedValues, setCheckedValues] = useState<any[]>([]); const options = [ 'Created', 'Processing', 'Picked', 'Packed', 'Completed', 'Cancelled', ]; const filtered = (type: any) => { let updatedCheckedValues; if (checkedValues.includes(type)) { // 移除已存在的类型 updatedCheckedValues = checkedValues.filter(item => item !== type); } else { // 添加新类型 updatedCheckedValues = [...checkedValues, type]; } setCheckedValues(updatedCheckedValues); // 根据选中的类型过滤数据 const filteredData = array.filter(item => updatedCheckedValues.includes(item.state)); setNewArray(filteredData); }; return ( <View style={{flex: 1, height: '100%'}}> <View style={styles.main}> <View style={styles.orgNameView}> <Text style={styles.orgData}>{data}</Text> </View> <View> <Text style={styles.fullfillmentText}>Fulfillments</Text> </View> <TouchableOpacity onPress={() => setModalVisibile(true)} style={styles.filterView}> <Image source={require('./src/Assets/fonts/levels.png')} style={styles.filterIcon} /> </TouchableOpacity> </View> <View style={styles.container}> <View style={styles.textInput}> <Search size={30} color="#808080" style={styles.search} /> <TextInput placeholder="Type to Search" value={search} onChangeText={query => setSearch(query)} /> </View> </View> <View style={{height: '80%'}}> <SearchItem data={array} search={search} setSearch={setSearch} isChecked={isChecked} data2={new_Array} setApply={setApply} /> </View> <TouchableWithoutFeedback> <Modal isVisible={modalVisibile} style={styles.modal}> <TouchableWithoutFeedback onPress={() => setModalVisibile(false)}> <View style={styles.modalView}> <View style={{ justifyContent: 'flex-start', alignItems: 'center', paddingVertical: 5, }}> <Text style={styles.topBar} /> </View> <View style={styles.filterHeadingView}> <Text style={styles.filterText}>Filters</Text> <TouchableOpacity onPress={() => { setNewArray([]); setIsChecked({ created: false, processing: false, picked: false, packed: false, completed: false, cancelled: false, }); setCheckedValues([]); }}> <Text style={styles.clearText}>Clear</Text> </TouchableOpacity> </View> <View style={styles.statusView}> <Text style={styles.statusText}>Status</Text> </View> <View style={styles.checkboxView}> <Text style={styles.checkItems}>{options[0]}</Text> <CheckBox style={styles.checkbox} disabled={false} value={isChecked.created} onValueChange={newValue => { setIsChecked({...isChecked, created: newValue}); filtered('Created'); }} /> </View> <View style={styles.checkboxView}> <Text style={styles.checkItems}>{options[1]}</Text> <CheckBox style={styles.checkbox} disabled={false} value={isChecked.processing} onValueChange={newValue => { setIsChecked({...isChecked, processing: newValue}); filtered('Processing'); }} /> </View> <View style={styles.checkboxView}> <Text style={styles.checkItems}>{options[2]}</Text> <CheckBox style={styles.checkbox} disabled={false} value={isChecked.picked} onValueChange={newValue => { setIsChecked({...isChecked, picked: newValue}); filtered('Picked'); }} /> </View> <View style={styles.checkboxView}> <Text style={styles.checkItems}>{options[3]}</Text> <CheckBox style={styles.checkbox} disabled={false} value={isChecked.packed} onValueChange={newValue => { setIsChecked({...isChecked, packed: newValue}); filtered('Packed'); }} /> </View> <View style={styles.checkboxView}> <Text style={styles.checkItems}>{options[4]}</Text> <CheckBox style={styles.checkbox} disabled={false} value={isChecked.completed} onValueChange={newValue => { setIsChecked({...isChecked, completed: newValue}); filtered('Completed'); }} /> </View> <View style={{flex: 1, height: getHeight(100)}}> <View style={styles.checkboxView}> <Text style={styles.checkItems}>{options[5]}</Text> <CheckBox style={styles.checkbox} disabled={false} value={isChecked.cancelled} onValueChange={newValue => { setIsChecked({...isChecked, cancelled: newValue}); filtered('Cancelled'); }} /> </View> </View> <View style={styles.applyButtonView}> <TouchableOpacity style={styles.buttonApply} onPress={() => { setModalVisibile(false); setApply(true); }}> <Text style={styles.buttonText}>Apply</Text> </TouchableOpacity> </View> </View> </TouchableWithoutFeedback> </Modal> </TouchableWithoutFeedback> </View> ); }; const styles = StyleSheet.create({ main: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: wp(5), paddingVertical: hp(2), backgroundColor: '#fff', elevation: 3, }, orgNameView: {}, orgData: { fontSize: hp(2), fontWeight: '600', }, fullfillmentText: { fontSize: hp(2.5), fontWeight: '700', }, filterView: {}, filterIcon: { width: wp(6), height: hp(3), }, container: { paddingHorizontal: wp(5), paddingVertical: hp(1), backgroundColor: '#fff', }, textInput: { flexDirection: 'row', alignItems: 'center', borderWidth: 1, borderColor: '#ccc', borderRadius: wp(2), paddingHorizontal: wp(3), paddingVertical: hp(1), }, search: { marginRight: wp(3), }, modal: { justifyContent: 'flex-end', margin: 0, }, modalView: { backgroundColor: '#fff', borderTopLeftRadius: wp(5), borderTopRightRadius: wp(5), paddingHorizontal: wp(5), paddingVertical: hp(2), height: hp(70), }, topBar: { width: wp(15), height: hp(0.5), backgroundColor: '#ccc', borderRadius: wp(1), }, filterHeadingView: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: hp(2), borderBottomWidth: 1, borderBottomColor: '#f0f0f0', }, filterText: { fontSize: hp(2.5), fontWeight: '700', }, clearText: { fontSize: hp(2), color: '#007AFF', fontWeight: '600', }, statusView: { paddingVertical: hp(2), }, statusText: { fontSize: hp(2), fontWeight: '600', color: '#333', }, checkboxView: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingVertical: hp(1.5), }, checkItems: { fontSize: hp(2), fontWeight: '500', }, checkbox: { width: wp(5), height: hp(2.5), }, applyButtonView: { paddingVertical: hp(2), }, buttonApply: { backgroundColor: '#007AFF', borderRadius: wp(2), paddingVertical: hp(2), alignItems: 'center', }, buttonText: { color: '#fff', fontSize: hp(2), fontWeight: '600', }, }); export default FullfillmentScreen;
关键修正点
- 将全局变量
checkedValues替换为useState状态变量,确保状态变化触发组件更新。 - 重构
filtered函数,通过判断类型是否存在来执行添加/移除逻辑,避免重复添加。 - 修正
new_Array的状态类型为数组,避免类型错误。 - 完善“Clear”按钮逻辑,同步重置
checkedValues、isChecked和new_Array状态。 - 补充了
Completed和Cancelled复选框的filtered调用,确保所有状态都能同步。
内容的提问来源于stack exchange,提问作者Muqsit Ali
相关产品推荐
相关产品推荐

