I've spent hours on this bug and I'm hoping another set of eyes can help me out! Appreciate you're help!
I have a React Native app and inside a Modal, I have a list of options with radio buttons.
What I want:
When you click on a TouchableHighlight item inside the model list, I'd like the radio button to move to the item the user presses. In other words, I want to set the radio button as selected
if I press on the rowId of the item I clicked.
What is happening: When I close the Modal and reopen, I see that the radio button has moved to the correct option, but the problem is that I need the radio button to move immediately when I click! So, I'm setting the correct state but the component isn't re-rendering until I reopen the Modal.
Here is my custom radio button component:
export default RadioButton = ({style, selected}) => {
return (
<View style={[{
height: 24,
width: 24,
borderRadius: 12,
borderWidth: 2,
borderColor: colors.primaryText,
alignItems: 'center',
justifyContent: 'center',
}, style]}>
{
selected ?
<View style={{
height: 16,
width: 16,
borderRadius: 8,
backgroundColor: colors.primaryText,
}}/>
: null
}
</View>
);
}
I have a container component handling the state:
class ShippingDetails extends Component {
constructor(props){
super(props)
const ds = new ListView.DataSource({rowHasChanged: (r1, r2, ) => r1 !== r2 });
const deliveryOptions = ['USPS Mail', 'USPS Next Day'] //will be replaces with redux
this.state = {
dataSource: ds.cloneWithRows(deliveryOptions),
shippingMethod: null,
modalVisible: false,
selectedOption: 0
};
}
_handleShippingMethodPress = (selected, id) => {
this.setState({shippingMethod: selected})
this.setState({selectedOption: id})
}
renderShippingMethods = (shippingMethod, sectionID, rowID, highlightRow) => {
return (
<SelectShippingMethod
onPress={() => this._handleShippingMethodPress(shippingMethod, rowID)}
shippingMethod={shippingMethod}
price={'Free Shipping'}
date={'Expected delivery March 12'}
selected={this.state.selectedOption == rowID}
/>
)
}
render () {
return (
<View style={backgroundApp}>
<View>
<SelectShippingMethod
shippingMethod={shippingMethod}
onPress={() => this.setModalVisible(true)}
price={'Free Shipping'} //replace with redux price
date={'Expected delivery March 12'}
singleRow={true}
/>
<Modal
animationType={"slide"} //slide and fade
transparent={false}
visible={this.state.modalVisible}
onRequestClose={()=>{console.warn('callback for onRequestClose Modal in ShippingDetails')}} //
>
<ShippingMethodOptions
dataSource={this.state.dataSource}
renderRow={this.renderShippingMethods}
renderSeparator={Separator}
closeModal={() => this.setModalVisible(false)}
/>
</Modal>
</View>
</View>
)
}
}
SelectShippingMethod is a component that returns the individual TouchableHighlight Items and is passed selected
as a prop from the container component.
return(
<TouchableHighlight
onPress={onPress}>
<View style={[rowWrapper, {alignItems: 'center', paddingLeft: 5}]}>
{ !singleRow && <RadioButton selected={selected}/>}
<View style={styles.methods}>
<Text style={descriptionColor}>{description}</Text>
<Text style={subHeader}>{shipDate}</Text>
</View>
<Text style={styles.price}>{shipPrice}</Text>
{/*<Icon name="ios-arrow-forward" size={17} color={colors.iconGrey} style={arrows}/>*/}
</View>
</TouchableHighlight>
)
ShippingMethodOptions is a component wraps around the ListView and passes the appropriate props down.
const ShippingMethodOptions = ({dataSource, renderRow, renderSeparator, closeModal}) => {
return(
<View style={backgroundApp}>
<NavHeader closeModal={closeModal}/>
<Text style={[subHeader, textSection]}></Text>
<View style={hr}></View>
<ListView
dataSource={dataSource}
renderRow={renderRow}
renderSeparator={renderSeparator}
/>
</View>
)
}
I noticed when I upgrade to React 16 with fiber that the radio buttons work as expected, so this makes me wonder a few things.
is fiber just so much faster that I can write buggier code?
is there something different about the life cycle method in the Modal component when using the updated React version?
is there something different about setState that causes more things to re-render with fiber?
UPDATE
I've console logged the process and I see that after pressing on an item the renderRow on the ListView is not called again but SelectedShippingMethod is called with an undefined
selected. Why does this happen and how can I get this working?