I am making custom radio button in react native.
Parent Component
const radioData = [
{ text: 'value A' },
{ text: 'value B' },
{ text: 'value C' },
];
<RadioButton
dataText={radioData}
isSelected={(selected) => {
console.log('<><>', selected);
}}
/>
Child Component
const RadioButton= (props) => {
const [selected, setSelected] = useState(false);
let { dataText, isSelected } = props;
return (
<>
{dataText.map((item) => {
return (
<View
style={{
flexDirection: 'row',
width: '50%',
marginVertical: 10,
}}
>
{selected ? (
<TouchableOpacity
onPress={() => {
if (selected) {
setSelected(false);
isSelected(false);
} else {
setSelected(true);
isSelected(true);
}
}}
>
<Image
source={require('../../assets/img/checkFullColor.png')}
style={{
width: 20,
height: 20,
marginRight: 20,
}}
resizeMode={'contain'}
/>
</TouchableOpacity>
) : (
<TouchableOpacity
onPress={() => {
if (selected) {
setSelected(false);
isSelected(false);
} else {
setSelected(true);
isSelected(true);
}
}}
>
<View
style={{
backgroundColor: Colors.accentDark,
height: 20,
width: 20,
borderRadius: 50,
marginRight: 20,
}}
/>
</TouchableOpacity>
)}
<Text style={{ color: Colors.accentDark }}>{item.text}</Text>
</View>
);
})}
</>
);
};
The Problem is even I click on any one of the RadioButton, then all 3 are getting selected or unselected.
I wanted a feature where I click on one of them then other gets unselected and selected value is updated in parent component.
Your RadioButton component should only render one radio button and not all at once. So you need to assign radioData in the parent component. Right now, the selected state is the same for all radio buttons assigned in your RadioButton component.
The relevant part of its main component:
const radioData = [ { text: 'value A' }, { text: 'value B' }, { text: 'value C' }, ]; return render ( <View> {radioData.map((item) => { <- map here <RadioButton dataText={item.text} /> }) </View> ); And remove the assignment in your RadioButton component.
/... return ( <> // {dataText.map((item) => { <- remove this /... If you want to have a component that renders many radio buttons, keep the assignment in your RadioButton component but also set the state for each radio button. I strongly recommend that you don't do that and limit your RadioComponent to an instance of a radio button.
I think your issue is that you try to use one Boolean to keep track of whether of the currently selected RadioButton. If you want to use booleans to keep track, then every radioData item would need a boolean and every time a selection was made, then every other boolean would be need to be updated. An easier approach would be to just keep track of the selected index, and compare indices: (Here's a snack demo)
import React,{
useState,
useEffect
} from 'react';
import {
View,
Image,
TouchableOpacity,
// FlatList,
Text,
StyleSheet
} from 'react-native';
export default function RadioButton({onSelection,options, defaultSelection}){
// instead of giving each list item an isSelected prop just keep
// track of the selected index
const [selectedIndex, setSelectedIndex] = useState(defaultSelection || 0)
// its much cleaner to use an effect to allow subscriptions to changes
useEffect(()=>{
onSelection(selectedIndex,options[selectedIndex])
},[selectedIndex])
return (
<View style={styles.container}>
{
options.map((item,index)=>{
return (
<TouchableOpacity style={styles.rowItem} onPress={()=>setSelectedIndex(index)}>
{index == selectedIndex &&
<Image
source={require('../../assets/snack-icon.png')}
style={{
width: 20,
height: 20,
marginRight: 20,
}}
resizeMode={'contain'}
/>
}
<Text>{item.text}</Text>
</TouchableOpacity>
)
})
}
</View>
)
}
const styles = StyleSheet.create({
container:{
width:'100%',
height:'20%',
flexDirection: 'row',
flexWrap:'wrap',
justifyContent:'space-between',
alignItems:'center'
},
row:{
},
rowItem:{
// width: '50%',
paddingVertical:10,
marginVertical: 10,
}
})
And the parent component:
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
import RadioButton from './src/components/RadioButton'
export default function App() {
const radioData = [
{ text: 'value A' },
{ text: 'value B' },
{ text: 'value C' },
];
return (
<View style={styles.container}>
<RadioButton
options={radioData}
onSelection={(index,value) => {
console.log('<><>', value);
}}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});