使复选框值在可重用组件中唯一。反应本机

问题描述 投票:0回答:1

编辑 - 我重新构建了流程以使其不那么冗长。希望这更容易消化

我有一组屏幕(黄色、橙色、绿色等),每个屏幕都有 5 张卡,用于显示视频缩略图、标题等数组。每张卡可以容纳任意数量的缩略图。用户将视频/缩略图添加到这些卡(集合)的方式是通过包含数据的模式,并且每个项目都有一个复选框。选择复选框并关闭模式后,它们将添加到卡片中。

这有效。除了,当我从另一张卡打开模式时,先前选择的复选框已被选中。我需要使用从打开它的卡中选择的复选框来打开每个模式

注意:复选框组件来自 React Native Paper - 请参阅此处。它没有

value
属性。它使用我已经在实施的
status

此外,每张卡都位于单独的文件中,以保持关注点分离,并且不会意外混合道具值。然而,该复选框坚持记住最后的选择。

这是黄屏的逻辑代码

// This function gets triggered by the checkbox selection and 
// populates the state `selectedwaza` 
// it also handles the checked and unchecked status
const selectItem = (item, index) => {
  const newData = [...dropdowndata];
  const newItem = newData[index];

  newItem.checked = !item.checked;
  setChecked(!checked)
  setDropdownData(newData);    

  if (newItem.checked) {
    if (!selectedwaza.includes(newItem)) {
      setSelectedWaza(prev => [...prev, newItem]); 
    }
  } else {
    setSelectedWaza(prev => prev.filter(i => i.title !== newItem.title));
  }
}

我认为如下:

// I mad the items to pick from and assign a checkbox to each item
{dropdown_collection.map((item, index) => {
    return (
      <View key={index}>
        <Text style={{color: activeColors.textcolor}} >
            {item.title}
        </Text> 
        <Checkbox.Item
            mode='android'
            color={activeColors.primary}
            status={item.checked ? 'checked' : 'unchecked'}
            onPress={() => selectItem(item, index)}
        />
      </View>
    )
  }
})}

编辑2我可以看到,尽管复选框保持选中状态,但它们的值并未保留。我仍然可以打开下一组卡片并选择我想要的内容,它只会添加新选择的内容并忽略上次使用中已经记住的内容。然而,这是不切实际的,因为如果我想添加一个已显示为选定的选项,我必须先取消选择它,然后再次选择它。我认为一个简单的“关闭模式时清除复选框”方法将是一个很好的技巧。但这也行不通。我正在发布有问题的函数,以防其他人看到这个并想帮助我

const selectItem = (item, index) => {

  const newData = [...dropdownCollection];
  const newItem = newData[index];

  newItem.checked = !item.checked;
  setChecked(!checked)  

  if (newItem.checked) {
    if (!selectedwaza.includes(newItem)) {
      setSelectedWaza(prev => [...prev, newItem]); 
    }
  } else {
    setSelectedWaza(prev => prev.filter(i => i.title !== newItem.title));
  }
}

// Function to clear all checkboxes
const handleCloseModal = () => {
  setModalVisible(false);
  const clearedData = dropdown_collection.map(item => ({
    ...item,
    checked: false
  }));
  // Update your state with the cleared data
  setDropdownCollection(clearedData);
};

对于那些需要更多代码来查看的人,请参阅下面的整个页面。其他只需要相关代码的人请忽略下面

import React, {useContext, useState, useRef, useEffect} from 'react';
import { StyleSheet, View, Text, TouchableOpacity, Image, Animated, Pressable, Modal, ActivityIndicator  } from 'react-native'
import { colors } from '../../../../assets/theme/config';
import { ThemeContext } from '../../../../context/ThemeContext';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { useNavigation } from '@react-navigation/native';
import { Checkbox } from 'react-native-paper';
import SearchField from '../../../../components/SearchField';
import ashiwaza from '../../../../assets/data/nagewaza/ashiwaza';
import koshiwaza from '../../../../assets/data/nagewaza/koshiwaza';
import masutemiwaza from '../../../../assets/data/nagewaza/masutemiwaza';
import yokosutemiwaza from '../../../../assets/data/nagewaza/yokosutemiwaza';
import tewaza from '../../../../assets/data/nagewaza/tewaza';

const dropdown_collection = [...tewaza, ...ashiwaza, ...koshiwaza, ...masutemiwaza, ...yokosutemiwaza]

import {db, auth} from '../../../../firebase';
import {onAuthStateChanged} from 'firebase/auth';
import { doc, getDoc, updateDoc, setDoc } from 'firebase/firestore';

const ITEM_SIZE = 180;
const ITEM_HEIGHT = 145;
const QTY = 8

const GokyoNowaza = () => {
  const [index, setIndex] = useState(0);
  const [waza, setWaza] = useState([])
  const [checked, setChecked] = useState(false)
  const [selectedwaza, setSelectedWaza] = useState([])
  const [dropdownCollection, setDropdownCollection] = useState(dropdown_collection);
  const [modalVisible, setModalVisible] = useState(false);
  const [value, setValue] = useState("");

  const isLoading = false
  const ref = useRef(null);
  const {theme} = useContext(ThemeContext)
  let activeColors = colors[theme.mode]
  const navigation = useNavigation();

  // build the collection from selecting the checkboxes
  const selectItem = (item, index) => {

    const newData = [...dropdownCollection];
    const newItem = newData[index];

    newItem.checked = !item.checked;
    setChecked(!checked)  

    if (newItem.checked) {
      if (!selectedwaza.includes(newItem)) {
        setSelectedWaza(prev => [...prev, newItem]); 
      }
    } else {
      setSelectedWaza(prev => prev.filter(i => i.title !== newItem.title));
    }
  }

  // Function to clear all checkboxes
  const handleCloseModal = () => {
    setModalVisible(false);
    const clearedData = dropdown_collection.map(item => ({
      ...item,
      checked: false
    }));
    // Update your state with the cleared data
    setDropdownCollection(clearedData);
  };

  //set collection to data
  const handleTestCollection = async () => {
    const userId = auth.currentUser.uid;
    const docRef = doc(db, 'useraccounts', userId);
  
    try {
      const docSnap = await getDoc(docRef);
  
      // Prepare the data to be set or updated
      const gokyuData = docSnap.exists() && docSnap.data().gokyu 
        ? docSnap.data().gokyu 
        : {};

      gokyuData.gokyoNoWaza = Array.isArray(selectedwaza) 
        ? [...selectedwaza] 
        : gokyuData.gokyoNoWaza || [];

      // Set or update the document
      await setDoc(docRef, { gokyu: gokyuData }, { merge: true });
      console.log("Document successfully updated!");
    } catch (error) {
      console.error("Error updating document: ", error);
    }
  }

  
  //display the colleciton on load
  useEffect(() => {
    const getUser = () => {        
      onAuthStateChanged(auth, (user) => {
        if(user) {      
          const userId = auth.currentUser.uid;
          user !== null || user !== undefined
          const docRef = doc(db, 'useraccounts', userId);        

          getDoc(docRef).then((docSnap) => {
            const data = docSnap.data().gokyu?.gokyoNoWaza || [];
            if (docSnap.exists()){
              setSelectedWaza(data);        
            } else {
              console.log("nothing here"); 
            }      
          });
        } 
      }); 
    }

    getUser();
  }, []);


  return (
    <View style={[{backgroundColor: activeColors.bgalt}, styles.card]}>
      <View style={styles.sectionLabelAndButton}>
        <View>
          <View>
            <Text style={[{color: activeColors.textcolor, fontSize:18, fontWeight:'bold'}]}>
              Gokyo No Waza  
            </Text>
          </View>
            
          <View>
            <Text style={[{color: activeColors.textcolor, fontSize:18, fontWeight:'normal'}]}>
              Select {QTY} throws 
            </Text>            
          </View> 
        </View>

        <View style={styles.buttons} >
          <TouchableOpacity 
            onPress={() => handleTestCollection()}  
            style={[{backgroundColor:activeColors.primary}, styles.addiconbutton]}>
            <Icon name="content-save" size={24} color={activeColors.white} />
          </TouchableOpacity>
          <TouchableOpacity 
            onPress={() => setModalVisible(true)}  
            style={[{backgroundColor:activeColors.primary}, styles.addiconbutton]}>
            <Icon name="plus" size={24} color={activeColors.white} />
          </TouchableOpacity>
        </View>        
      </View>  

      <Animated.FlatList
        ref={ref}
        data={selectedwaza}
        horizontal
        initialNumToRender={10}
        initialScrollIndex={index}
        keyExtractor={(item, index) => index.toString()}
        showsHorizontalScrollIndicator={false}
        snapToInterval={ITEM_SIZE}
        snapToOffsets={[...Array(waza.length).keys()].map(i => i * ITEM_SIZE)}
        decelerationRate={0}
        bounces={false}
        scrollEventThrottle={16}
        onEndReachedThreshold={0.5}
        onEndReached={() => {
          setWaza([...waza]);
        }}
        contentContainerStyle={{
          alignItems: 'flex-start',
        }}
        renderItem={
          ({item, index: fIndex}) => {
            return (
              <View key={fIndex} style={{width:ITEM_SIZE * .6, marginVertical:20, marginRight: 20}}> 
                <View style={[{color: activeColors.textcolor, backgroundColor: activeColors.bgalt,}, styles.counter]}>
                  <Text style={{color: activeColors.textcolor}}>{fIndex + 1}</Text> 
                </View>    
                <View style={[styles.overlay]}>
                  <TouchableOpacity 
                    onPress={() => navigation.navigate('TechniqueDetails', {data: item})}  
                    style={[{backgroundColor:activeColors.primary}, styles.playbutton]}>
                    <Icon name="play" size={24} color={activeColors.white} />
                  </TouchableOpacity>                  
                </View>
                <Animated.View>         
                  <Image source={{ uri: `https://judopedia.wiki/assets/images/${item.thumbnail}` }} 
                  style={styles.thumbnail}/>
                  <Text 
                    numberOfLines={2}
                    style={{
                      width: ITEM_SIZE * .6,
                      color:activeColors.textcolor, 
                      fontWeight: 'bold'
                    }}>  
                    {item.title} 
                  </Text>   
                </Animated.View>   
              </View>   
            )
          }
        }
      />
      <Modal animationType="slide" visible={modalVisible} transparent={true}>
        <View 
          style={[{backgroundColor: activeColors.overlay}, styles.container]}>
          {isLoading && <ActivityIndicator size={70} color={colors.tertiary} />}

          {!isLoading && (
            <View style={[styles.modalView, { backgroundColor: activeColors.bgalt }]}>
              <View style={{width: "100%", alignItems: "center", justifyContent:"space-between", flexDirection:"row"}}>
                <Text style={[{color:activeColors.primary }, styles.modalheading]}>
                  Techniques
                </Text>
                <Pressable onPress={handleCloseModal}>
                  <Icon name="close" size={24} color={activeColors.textcolor} />
                </Pressable>
              </View>
              
              <View style={styles.decisionRow}>
                <SearchField value={value} onChangeText={setValue} style={{backgroundColor: activeColors.bg}} />
                <View style={[{backgroundColor: activeColors.bgalt}, styles.searchcontainer]}>
                  {dropdown_collection.map((item, index) => {
                    if(value === "" ) {
                      return null
                    } else if(
                        item.title.toLowerCase().includes(value.toLowerCase()) || item.english.toLowerCase().includes(value.toLowerCase())
                      ) 
                    {
                      return (
                        <View key={index} style={styles.searchitems}>
                          <View style={styles.metadata}>
                            <Image source={{ uri: `https://judopedia.wiki/assets/images/${item.thumbnail}` }} style={styles.searchresultsthumbnail}/>
                            <View>
                              <Text style={{color: activeColors.textcolor}} >{item.title}</Text>
                              <Text style={{color: activeColors.textcolor, fontSize:12}} >{item.english}</Text>
                            </View>  
                          </View>
                          <View style={styles.buttongroup}>
                            <Checkbox.Item
                              mode='android'
                              color={activeColors.primary}
                              status={item.checked ? 'checked' : 'unchecked'}
                              onPress={() => selectItem(item, index)}
                            />
                          </View>   
                        </View>
                      )
                    }
                  })}
                </View>
              </View>
            </View>
          )}
        </View>
      </Modal>
    </View>
  )
}

export default GokyoNowaza
javascript reactjs react-native
1个回答
0
投票

在您在此部分提供的代码中:

dropdown_collection.map((item, index) => {
  if (value === '') {
    return null;
  } else if (
    item.title.toLowerCase().includes(value.toLowerCase()) ||
    item.english.toLowerCase().includes(value.toLowerCase())
  ) {
    return (
      <View key={index} style={styles.searchitems}>
        <View style={styles.metadata}>
          <Image
            source={{ uri: `https://judopedia.wiki/assets/images/${item.thumbnail}` }}
            style={styles.searchresultsthumbnail}
          />
          <View>
            <Text style={{ color: activeColors.textcolor }}>{item.title}</Text>
            <Text style={{ color: activeColors.textcolor, fontSize: 12 }}>{item.english}</Text>
          </View>
        </View>
        <View style={styles.buttongroup}>
          <Checkbox.Item
            mode='android'
            color={activeColors.primary}
            status={item.checked ? 'checked' : 'unchecked'}
            onPress={() => selectItem(item, index)}
          />
        </View>
      </View>
    );
  }
});

您应该绘制状态图而不是

dropdown_collection
handleCloseModal
清除状态
dropdownCollection
的数据,但您正在返回
dropdown_collection

© www.soinside.com 2019 - 2024. All rights reserved.