React native changing button color not working properly

Viewed 71

I have my reusable component for Button :

   import React, { Component } from "react";
import { View, Text, TouchableOpacity } from "react-native";

import { styles } from "./styles";

class TransactionFees extends Component {
  state = {
    pressed: false,
  };

  render() {
    const { pressed } = this.state;
    const { speed, eth, usd } = this.props;
    return (
      <View>
        <TouchableOpacity  style={ pressed ? styles.pressedButton : null } onPress={() => this.setState({ pressed: !pressed })}>
          <Text style={styles.transactionFeeTitle}>{speed}</Text>
          <Text style={styles.transactionFeeSubText}>{eth} ETH</Text>
          <Text style={styles.transactionFeeSubText}>$ {usd} </Text>
        </TouchableOpacity>
      </View>
    );
  }
}

export default TransactionFees;

This is how I use it in another component :

<View style={styles.transactionFeeChoices}>
        <TransactionFees speed={"Slow"} eth={"0.000010"} usd={"0.02"} />
        <TransactionFees speed={"Average"} eth={"0.000030"} usd={"0.03"} />
        <TransactionFees speed={"Fast"} eth={"0.000050"} usd={"0.04"} />
      </View>

When i press the button the background color changes to blue and the problem is When I click on second button,the first button is not going to default background color

Any solutions on how to solve this please?

3 Answers

The way your TransactionFees component is currently created means that each TransactionFees occurrence has its own internal state. So when one TransactionFees changes, that doesn't mean the others are automatically updated. You can see them as autonomous components.

In your case however, the TransactionFees occurrences shouldn't be automomous, a change in one occurence should reflect in the others. This is a classic react pattern where the most common solution is to "lift the state up" from the TransactionFeeds component into the parent. There even is a react article about in the official docs

Steps to take

  1. have one state variable in the parent that keeps the selected TransactionFees
  2. pass in pressed as a prop to the TransactionFees occurrences
  3. pass in a change handler function that the TransactionFees component can call when one of the buttons is pressed

In code, this will be more or less:


class Manager extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selected: '',
    };
  }

  onChangeSelection = selected => {
    this.setState({
      selected,
    });
  } 

  render() { 
    const { selected } = this.state;
    return (
      <View style={styles.transactionFeeChoices}>
        <TransactionFees speed={"Slow"} eth={"0.000010"} usd={"0.02"} pressed={selected === 'Slow'} onPress={() => this.onChangeSelection('Slow')} />
        <TransactionFees speed={"Average"} eth={"0.000030"} usd={"0.03"} pressed={selected === 'Average'} onPress={() => this.onChangeSelection('Average')} />
        <TransactionFees speed={"Fast"} eth={"0.000050"} usd={"0.04"} pressed={selected === 'Fast'} onPress={() => this.onChangeSelection('Fast')} />
      </View>
    );
  }

}

class TransactionFees extends Component {
  render() {
    const { speed, eth, usd, pressed, onPress } = this.props;
    return (
      <View>
        <TouchableOpacity  style={ pressed ? styles.pressedButton : null } onPress={onPress}>
          <Text style={styles.transactionFeeTitle}>{speed}</Text>
          <Text style={styles.transactionFeeSubText}>{eth} ETH</Text>
          <Text style={styles.transactionFeeSubText}>$ {usd} </Text>
        </TouchableOpacity>
      </View>
    );
  }
}

You have created 3 instances of TransactionFees and they will have their own separate state. That's why click on the second button does not change the state of the first button.

If you want to make either of button-click trigger that style change, you need to use shared value between all those TransactionFees instances.

There can be 2 ways to do this depending on where to store that value

  1. You can store it as a state of the parent component and pass it down to TransactionFees component

  2. You can store it in redux store and use it inside TransactionFees by connecting the component to the store.

To do so

You need to keep the stat in the parent

And pass to each button the function to change the state

And move the current stat to each button

like this

<TransactionFees speed={"Slow"}
  setClicked(()->{
     this.setState({clicked:true})
  clicked={this.state.clicked} 
  eth={"0.000010"} usd={"0.02"} 
/>
Related