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

React Native中如何实现复选框控制数组筛选与状态更新?

React Native复选框筛选状态同步问题修复

问题描述

开发包含多复选框的Modal筛选功能时,勾选复选框可将对应值存入checkedValues数组并通过setNewArray更新状态,FlatList基于该状态展示数据。但取消勾选时,无法从checkedValues数组移除对应值,无论勾选/取消操作,值都会被添加到数组中。

错误原因分析

  1. 全局变量误用:使用全局变量checkedValues而非React状态,变量变化无法触发组件重新渲染,状态更新不同步。
  2. 逻辑局限性:最初的filtered函数仅判断isChecked.created的状态,未处理其他复选框类型,且无论条件是否满足,都会执行checkedValues.push(type),导致值始终被添加。
  3. 状态类型错误:new_Array的状态类型声明为string,实际应定义为数组类型。

修复方案

  1. 将checkedValues改为React状态变量,确保变化能触发组件更新。
  2. 重构filtered函数:根据当前类型是否已存在于checkedValues中,决定执行添加或移除操作,再重新筛选数据更新new_Array。
  3. 修正new_Array的状态类型为数组。
  4. 优化“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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 18:27:01