Estoy haciendo un botón de opción personalizado en reaccionar nativo.
Componente principal
const radioData = [ { text: 'value A' }, { text: 'value B' }, { text: 'value C' }, ]; <RadioButton dataText={radioData} isSelected={(selected) => { console.log('<><>', selected); }} />Componente hijo
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> ); })} </> ); };El problema es que incluso hago clic en cualquiera de los botones de radio, luego los 3 se seleccionan o deseleccionan.
Quería una función en la que haga clic en uno de ellos, luego otro se deselecciona y el valor seleccionado se actualiza en el componente principal.
Su componente RadioButton solo debe representar un botón de opción y no todos a la vez. Por lo tanto, debe asignar radioData en el componente principal. En este momento, el estado selected es el mismo para todos los botones de radio asignados en su componente RadioButton .
La parte relevante de su componente principal:
const radioData = [ { text: 'value A' }, { text: 'value B' }, { text: 'value C' }, ]; return render ( <View> {radioData.map((item) => { <- map here <RadioButton dataText={item.text} /> }) </View> ); Y elimine la asignación en su componente RadioButton .
/... return ( <> // {dataText.map((item) => { <- remove this /... Si desea tener un componente que represente muchos botones de radio, mantenga la asignación en su componente RadioButton pero también establezca el estado para cada botón de radio. Le recomiendo encarecidamente que no haga eso y limite su RadioComponent a una instancia de un botón de opción.
Creo que su problema es que intenta usar un valor booleano para realizar un seguimiento del RadioButton seleccionado actualmente. Si desea utilizar valores booleanos para realizar un seguimiento, entonces cada elemento de radioData necesitaría un valor booleano y cada vez que se hiciera una selección, entonces sería necesario actualizar todos los demás valores booleanos. Un enfoque más fácil sería simplemente realizar un seguimiento del índice seleccionado y comparar índices: (Aquí hay una demostración de refrigerio )
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, } })Y el componente padre:
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', }, });