Adamski
Adamski

Reputation: 3675

React Native component opacity not updating when props updated

I have a React Native child component, which renders a button in a semi-transparent state if the disabled prop is set to true. The prop is likely to be updated after the app initially loads (once it has got its data), so will not be the initial state of the component.

I can see that once I interact with the button it changes its state, but for some reason not before. I can see, both from the logs and from the onPress behaviour, that the prop is updating. I've tried different approaches but none seemed to fix the issue.

class TestButton extends React.Component {

  constructor(props) {
    super(props);
  }

  render() {
    const buttonOpacity = (this.props.disabled  ? disabledOpacity : 1.0);
    console.log ("test disabled", this.props.disabled, buttonOpacity);

    return (
      <BubbleText style={{opacity: buttonOpacity}} onPress={
        () => ! this.props.disabled && doSomething() }>
          { this.props.testNumber }
      </BubbleText>
    );
  }
}

Upvotes: 12

Views: 3311

Answers (5)

Otavio
Otavio

Reputation: 11

Use TouchableOpacity from react-native-gesture-handler, it has a prop called containerStyle, your TouchableOpacity will automatically update opacity when "this.props.is_disabled" be false or true. Without it, you will need to restart application to show opacity:

<TouchableOpacity onPress={() => {}} 
                    disabled={this.props.is_disabled} 
                    containerStyle={{
                        opacity: this.props.is_disabled ? 1 : .4,
                    }}
                    style={}>
                </TouchableOpacity>

Upvotes: 0

kgstew
kgstew

Reputation: 481

There does seem to be an issue with setting the opacity of TouchableOpacity buttons. I'm using [email protected]. If the opacity is set and then updated the new render does not seem to change the opacity value even though it is being passed to the component style.

There is a native way to do this with TouchableOpacity. This also benefits from disabling all press events if using the disabled prop.

<TouchableOpacity
    disabled={ this.props.is_disabled }
    activeOpacity={ this.props.is_disabled ? .6 : 1 }>
    <Text>Custom Button</Text>
</TouchableOpacity>

One caveat to the above, setting the activeOpacity does not appear to change the text opacity only the backgroundColor.

Alternatively using rgba values to specify the opacity does work.

export class CustomButton extends Component {

    get_button_style() {
        let _button_style = [this.props.button_style]

        if (this.props.is_disabled) {
            _button_style.push({
                backgroundColor: 'rgba(0, 0, 0, .6')
            });
        }

        return _button_style;
    }

    render() {
        return(
            <TouchableOpacity
                style= { this.get_button_style() }>
                <Text> Custom Button </Text>
            </TouchableOpacity>
        )
    }
}

Upvotes: 12

Pnar Sbi Wer
Pnar Sbi Wer

Reputation: 478

Seems like a known issue https://github.com/facebook/react-native/issues/17105

One workaround is to wrap your TouchableOpacity's content in a view and apply the opacity styling to that view instead of directly to Touchable opacity.

Upvotes: 2

Adamski
Adamski

Reputation: 3675

The underlying component was a TouchableOpacity. It seems there is an issue with setting its opacity externally. I solved the issue in this case by defining colours explicitly, not using opacity:

class TestButton extends React.Component {

  constructor(props) {
    super(props);
  }

  render() {
      return (
        <BubbleText fill={this.props.disabled ? disabledFill : undefined} textStyle={this.props.disabled ? {color: disabledText} : {}} onPress={
          () => ! this.props.disabled && loadTest(this.props.navigator, this.props.set + this.props.testNumber, this.props.children)
          }>
            { this.props.testNumber }
          </BubbleText>
          );

  }
}

In another part of my code, I added a conditional to render a component as a View with opacity if disabled, and a TouchableOpacity if not.

Upvotes: 0

Nemi Shah
Nemi Shah

Reputation: 876

It's hard to say just from the snippet, it's possible that the problem is in the parent component using this one. Adding the code for that might help identify what the problem is.

Sorry dont have enough rep to add a comment.

Upvotes: 0

Related Questions