I have a strange issue with the TouchableOpacity
component. I have a MainButton
component which takes 2 props, item
and disabled
. Based on the the disabled
prop I want my MainButton component to apply a different style. The problem is when the TouchableOpacity
component re renders, it does not refresh the style. The prop disabled
is correctly set on re render.
What makes this strange is that if i change it to a TouchableHeighlight
it works as expected.
Does anyone know why? Is this a bug in TouchableOpacity?
import React, { Component } from 'react'
import UI from '../styles/ui'
import {
Text,
TouchableOpacity
} from 'react-native'
const ui = new UI()
const styles = ui.styles
class MainButton extends Component {
constructor (props) {
super(props)
this.state = {
disabled : props.disabled,
item: props.item
}
}
componentWillReceiveProps(props) {
this.setState({disabled:props.disabled})
}
render() {
var normalStyles = [styles.mainButton,styles.widthEighty]
var disabledStyle = [styles.mainButton,styles.widthEighty,styles.lowOpacity]
var correctStyles = this.state.disabled ? disabledStyle : normalStyles
console.log(this.state.disabled,'this.state.disabled ? ');
return (
<TouchableOpacity disabled={this.state.disabled} style={correctStyles} accessibilityLabel={this.state.item.name} onPress={this.state.item.onPress.bind(this)}>
<Text style={styles.mediumLabel}>{this.state.item.name}</Text>
</TouchableOpacity>
);
}
}
export { MainButton as default }
First, I don't think pass the disabled
and item
props to state.
You can directly do it in this way and get rid of constructor as well as componentWillReceiveProps
.
componentWillReceiveProps
lifecycle method will be deprecated soon, so they don't encourage its usage.
Also if possible, separate event handler from item
props.
It's not best way to do that
render () {
const { disabled, item, onPress } = this.props;
const { name } = item;
...
return (
...
<TouchableOpacity
disabled={disabled}
style={disabled ? disabledStyle : normalStyle}
accessibilityLabel={name}
onPress={onPress}
>
<Text style={styles.mediumLabel}>{name}</Text>
</TouchableOpacity>
...
);
}
The workaround I came up with is to use
setOpacityTo(value)
in order to update the canvas.
I did this componentDidUpdate()
as this lifecycle method get's called whenever your new style has been applied within your component. So I gave the <TouchableOpacity/>
component a ref
and updated it whenever it's style did change.
Example:
import React, { Component } from 'react'
import UI from '../styles/ui'
import {
Text,
TouchableOpacity
} from 'react-native'
const ui = new UI()
const styles = ui.styles
class MainButton extends Component {
constructor (props) {
super(props)
this.state = {
disabled : props.disabled,
item: props.item
}
}
componentWillReceiveProps(props) {
this.setState({disabled:props.disabled})
}
componentDidUpdate() {
this.refs['touchable'].setOpacityTo(1.0);
}
render() {
var normalStyles = [styles.mainButton,styles.widthEighty]
var disabledStyle = [styles.mainButton,styles.widthEighty,styles.lowOpacity]
var correctStyles = this.state.disabled ? disabledStyle : normalStyles
console.log(this.state.disabled,'this.state.disabled ? ');
return (
<TouchableOpacity ref={'touchable'} disabled={this.state.disabled} style={correctStyles} accessibilityLabel={this.state.item.name} onPress={this.state.item.onPress.bind(this)}>
<Text style={styles.mediumLabel}>{this.state.item.name}</Text>
</TouchableOpacity>
);
}
}
export { MainButton as default }
If you use opacity style (which using by TouchableOpacity), you should set this style for children of TouchableOpacity (ex a View) like this:
<TouchableOpacity
disabled={disabled}
accessibilityLabel={name}
onPress={onPress}
>
<View style={disabled ? disabledStyle : normalStyle}>
<Text style={styles.mediumLabel}>{name}</Text>
</View>
</TouchableOpacity>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With