1

I have a component that looks like this:

const criteriaList = [
  'Nur Frauen',
  'Freunde Zweiten Grades',
];

export const FilterCriteriaList: React.FunctionComponent = () => {
  const [state, setState] = useState(false);

  useEffect(() => {
    console.log('state is,', state);
  });

  const myFunction = () => {
    console.log('checking state', state);
    if (state == false) {
      setState(true);
    } else {
      setState(false);
    }
  };

  return (
    <View style={styles.container}>
      <View style={styles.horizontalLine} />
      {criteriaList.map((item: string, index: number) => (
        <View key={index}>
          <View style={styles.criteriaRow}>
            <TouchableOpacity 
              onPress={() => {
                myFunction();
              }}>
              <Icon
                name="circle-thin"
                color="#31C283"
                size={moderateScale(20)}
              />
            </TouchableOpacity>
            <Text style={styles.text}>{item}</Text>
          </View>
          
          <View style={styles.horizontalLine} />
        </View>
      ))}
    </View>
  );
};

Currently, I am using the circle-thin icon. I want to change it such that everytime I click on an icon, it changes to the dot-circle-o icon. Like radio buttons. However, I am not quite sure how to do so.

I thought of using ternary operators but since I am mapping my fields Idk how to setStates collectively. Maybe using the index? I don't want to make a separate state for each field. Here's a similar snack demo:

https://snack.expo.io/toTSYc2fD

I want to be able to select multiple/unselect options. I don't want to apply the same rule on all fields together.

Note: the onPress function can also be used on the Icon directly instead of the TouchableOpacity (though it is not preferred)

2 Answers2

1

Using a ternary sounds like the right approach to me. Can you not do something like:

name={state ? 'dot-circle-o' : 'circle-thin'}

You could also refactor your function:

 const myFunction = () => {
    console.log('checking state', state);
    setState(!state)
 };

If you have multiple fields then there are many ways to handle it. You could call useState multiple times, eg:

const [field1, setField1] = useState(false);
const [field2, setField2] = useState(false);

You could also store all fields in the same state:

const [state, setState] = useState({field1: false, field2: false});

...

  const myFunction = (fieldName) => {
    console.log('checking state', state);
    setState({...state, [fieldName]: !state[fieldName]})
  };

I guess you'd then use the item as the "fieldName? In which case:

return (
    <View style={styles.container}>
      <View style={styles.horizontalLine} />
      {criteriaList.map((item: string, index: number) => (
        <View key={index}>
          <View style={styles.criteriaRow}>
            <TouchableOpacity 
              onPress={() => {
                myFunction(item);
              }}>
              <Icon
                name={state[item] ? 'dot-circle-o' : 'circle-thin'}
                color="#31C283"
                size={moderateScale(20)}
              />
            </TouchableOpacity>
            <Text style={styles.text}>{item}</Text>
          </View>
          
          <View style={styles.horizontalLine} />
        </View>
      ))}
    </View>
  );

And to create the initial state:

const initialState = {}
criteriaList.forEach(item => initialState[item] = false)
const [state, setState] = useState(initialState);

dbramwell
  • 1,298
  • 6
  • 11
  • But how will I setStates? I want to be able to select multiple/unselect options. This will apply the same rule to all fields. –  Aug 04 '20 at 08:34
  • Seems like a good approach. Could you also add how I can pass the filedname on onPress directly then? Also, how will I check for it within the ternary operator? –  Aug 04 '20 at 08:42
  • So, in ```useState({field1: false, field2: false})``` I should use fieldnames(strings) as field1 field2 etc? –  Aug 04 '20 at 08:47
  • Updated for setting initial state – dbramwell Aug 04 '20 at 09:00
0

The code would be something like below. You have to set the index of the selected item as the state and use it to chose the icon.

const criteriaList = [
  {title:'My List',checked:false},
  {title:'Friends listt',checked:false},
  {title:'Not Good',checked:false},
  {title:'Sweet and sour',checked:false},
  {title:'Automatic',checked:false},
];

export const FilterCriteriaList: React.FunctionComponent = () => {
  const [state, setState] = useState(criteriaList);

  useEffect(() => {
    console.log('state is,', state);
  });

  const myFunction = (index) => {
    console.log('checking state', state);
    const arr=[...state];
    
    arr[index].checked=arr[index].checked?false:true;
    setState(arr);
    
  };

  return (
    <View style={styles.container}>
      <View style={styles.horizontalLine} />
      {criteriaList.map((item: Any,index:number) => (
        <View key={item}>
          <View key={item} style={styles.criteriaRow}>

              <Icon 
                style={styles.icon}
                name={item.checked?"circle":"circle-thin"}
                color="#31C283"
                size={moderateScale(20)}
                onPress= {()=>myFunction(index)}
              />
            <Text style={styles.text}>{item.title}</Text>
          </View>
          
          <View style={styles.horizontalLine} />
        </View>
      ))}
    </View>
  );
};
Guruparan Giritharan
  • 15,660
  • 4
  • 27
  • 50