Search code examples
react-nativeselecttouchableopacity

React Native - How to select all items and unselect again when one of selected items is clicked


What I have been trying is to make Select All button. And one of selected items is clicked, I want Select All button to be unselected, but my code doesn't show me this. When I click Select All button, it selects all, but the rest of items don't act anything.

AuthJoin :

import React, { useState } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import colors from '#common/colors';
import CheckBoxWithoutSquare from '#components/Box/CheckBoxWithoutSquare';


const styles = StyleSheet.create({
  container: {
    flexGrow: 1,
    marginTop: 100,
  },
  displayNone: {
    display: 'none',
  },
  joinForm: {
    height: 440,
    flexGrow: 0,
  },
  textStyle: {
    fontSize: 13,
    fontWeight: 'normal',
    color: colors.black,
  },
  checkContainer: {
    marginHorizontal: 15,
  },
  checkBox: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  checkText: {
    marginLeft: 10,
    fontSize: 13,
    fontWeight: 'normal',
    color: colors.black,
  },
  underline: {
    textDecorationLine: 'underline',
    fontSize: 13,
    fontWeight: 'normal',
    color: colors.black,
  },
  btnStyle: {
    backgroundColor: colors.iris,
    height: 50,
    position: 'absolute',
  },
});

const agreements = [
  {
    content: 'test1',
    checked: false,
  },
  {
    content: 'test2',
    checked: false,
  },
];

const AuthJoin = (props) => {
  const [data, setData] = useState(agreements);

  const [isChecked, setIsChecked] = useState(true);
  const checkAll = () => {
    let temp = data.map((item) => {
      return { ...item, checked: true };
    });
    setData(temp);

    console.log(temp);
  };
  const checkOne = (newValue, index) => {
    let temp = data.map((item, i) => {
      return index === i ? { ...item, checked: newValue } : item;
    });
    setData(temp);
    setIsChecked(!isChecked);
  };

  return (
    <>
      <View style={[styles.container]}>
        <View style={[styles.checkContainer]}>
          <View style={[styles.checkBox, { marginBottom: 20 }]}>
            <CheckBox onPress={checkAll} size={20} />
            <Text style={[styles.checkText]}>Select All</Text>
          </View>

          {data.map((item, index) => (
            <View
              style={[styles.checkBox, { justifyContent: 'space-between' }]}
            >
              <View style={[styles.checkBox, { marginBottom: 10 }]}>
                <CheckBoxWithoutSquare
                  // isChecked={!isChecked}
                  onPress={(newValue) => checkOne(newValue, index)}
                />
                <Text style={[styles.checkText]}>{item.content}</Text>
              </View>
              <TouchableOpacity>
                <Text style={[styles.underline]}>보기</Text>
              </TouchableOpacity>
            </View>
          ))}

        </View>
      </View>
    </>
  );
};

export default AuthJoin;

CheckBoxWithoutSquare :

const styles = StyleSheet.create({
  container: {
    width: 20,
    height: 20,
    justifyContent: 'center',
    alignItems: 'center',
  },
});

const CheckBoxWithoutSquare = ({ isChecked, onPress, size = 20 }) => {
  return (
    <TouchableOpacity style={[styles.container]} onPress={onPress}>
      <Image
        style={{ width: 15, height: 15 }}
        source={isChecked ? assets.icon_check_on : assets.child_checked_off}
      />
    </TouchableOpacity>
  );
};

CheckBox :

const CheckBox = ({ isChecked, onPress, size = 15 }) => {
  return (
    <TouchableOpacity style={{ width: size, height: size }} onPress={onPress}>
      <Image
        style={{ width: size, height: size }}
        source={isChecked ? assets.icon_check_on : assets.checked_off}
      />
    </TouchableOpacity>
  );
};

CheckBox.propTypes = {};

export default CheckBox;

I have googled, but still don't get it. I feel like I should make useState with array, and didn't go further after that. What should I do?


Solution

  • Here is the working example: Expo Snack

    enter image description here

    import React, { useState } from 'react';
    import { StyleSheet, Text, TouchableOpacity, View, Image } from 'react-native';
    import { AntDesign } from '@expo/vector-icons';
    
    const CheckBox = ({ isChecked, onPress, size = 15 }) => {
      return (
        <TouchableOpacity style={{ width: size, height: size }} onPress={onPress}>
          {isChecked ? (
            <Image
              style={{ width: size, height: size }}
              source={require('./assets/green.png')}
            />
          ) : (
            <Image
              style={{ width: size, height: size }}
              source={require('./assets/grey.png')}
            />
          )}
        </TouchableOpacity>
      );
    };
    
    const CheckBoxWithoutSquare = ({ isChecked, onPress, size = 20 }) => {
      return (
        <TouchableOpacity style={[styles.container]} onPress={onPress}>
          {isChecked ? (
            <Image
              style={{ width: size, height: size }}
              source={require('./assets/green.png')}
            />
          ) : (
            <Image
              style={{ width: size, height: size }}
              source={require('./assets/grey.png')}
            />
          )}
        </TouchableOpacity>
      );
    };
    
    const styles = StyleSheet.create({
      container: {
        flexGrow: 1,
        marginTop: 100,
      },
    
      checkContainer: {
        marginHorizontal: 15,
      },
      checkBox: {
        flexDirection: 'row',
        alignItems: 'center',
      },
      checkText: {
        marginLeft: 10,
        fontSize: 13,
        fontWeight: 'normal',
        color: 'black',
      },
      underline: {
        textDecorationLine: 'underline',
        fontSize: 13,
        fontWeight: 'normal',
        color: 'black',
      },
    });
    
    const agreements = [
      {
        content: 'test1',
        checked: false,
      },
      {
        content: 'test2',
        checked: false,
      },
    ];
    
    const AuthJoin = (props) => {
      const [data, setData] = useState(agreements);
      const [isChecked, setIsChecked] = useState(true);
      const [selectAll, setSelectAll] = useState(
        data.filter((item) => item.checked).length === data.length
      );
      const checkAll = () => {
        let newValue = data.filter((item) => item.checked).length === data.length;
        let temp = data.map((item) => {
          return { ...item, checked: !newValue };
        });
        setData(temp);
    
        console.log(temp);
      };
      const checkOne = (newValue, index) => {
        let temp = data.map((item, i) => {
          return index === i ? { ...item, checked: newValue } : item;
        });
        setData(temp);
        setIsChecked(!isChecked);
      };
    
      return (
        <>
          <View style={[styles.container]}>
            <View style={[styles.checkContainer]}>
              <View style={[styles.checkBox, { marginBottom: 20 }]}>
                <CheckBox
                  isChecked={
                    data.filter((item) => item.checked).length === data.length
                  }
                  onPress={checkAll}
                  size={20}
                />
                <Text style={[styles.checkText]}>Select All</Text>
              </View>
    
              {data.map((item, index) => (
                <View
                  style={[styles.checkBox, { justifyContent: 'space-between' }]}>
                  <View style={[styles.checkBox, { marginBottom: 10 }]}>
                    <CheckBoxWithoutSquare
                      isChecked={item.checked}
                      onPress={() => checkOne(!item.checked, index)}
                    />
                    <Text style={[styles.checkText]}>{item.content}</Text>
                  </View>
                  <TouchableOpacity>
                    <Text style={[styles.underline]}>보기</Text>
                  </TouchableOpacity>
                </View>
              ))}
            </View>
          </View>
        </>
      );
    };
    
    export default AuthJoin;