React native changing button color not working properly - react-native

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?

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
have one state variable in the parent that keeps the selected TransactionFees
pass in pressed as a prop to the TransactionFees occurrences
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
You can store it as a state of the parent component and pass it down to TransactionFees component
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

How to disable one button when another button is pressed in react-native-paper

In react-native-paper (or even in react-native dirctly) I don't understand how to do the equivalent of getElementById to modify an element. In JavaScript, I would assign each button a unique id, and then when one button is clicked, I can call function that will disable/enable the other button based on its id.
However I am not seeing how to accomplish this task in react-native-paper (or react-native either).
Here is sample code:
import React from 'react';
import {View, Alert} from 'react-native';
import {Button} from 'react-native-paper';
export default class App extends React.Component {
render() {
return (
<View>
<Button mode="contained" color="green" onPress={() => this.buttonOnePressed()}>Button One</Button>
<Button mode="contained" color="red" onPress={() => this.buttonTwoPressed()}>Button Two</Button>
</View>
);
}
buttonOnePressed() {
// If Button Two is disabled, then enable it.
// If Button Two is enabled, then disable it.
Alert.alert('Button ONE pressed');
}
buttonTwoPressed() {
// Do something when Button Two is pressed
Alert.alert('Button TWO pressed');
}
}
In your code make a state for the 1st button and another state for the 2nd button. Then by handling the state of the 2, you can achieve what you want
Here's a sample code:
export class default Test extends React.Component{
constructor(props){
super(props);
this.state = {
firstButtonEnable: false,
secondButtonDisable: false,
}
this.handlingButton = this.handlingButton.bind(this)
}
handlingButton(){
firstButtonEnable
? this.setState({secondButtonDisable: true})
: null;
}
render(){
return(
<View>
<Button title='Button1' onPress={() => {
this.setState({firstButtonEnable: true});
handlingButton();
}} />
<Button disabled={secondButtonDisable} title='Button2' } />
</View>
)
}
}

Get user input from input field in react similar to getElementById in react native using props

I am doing a loan calculation app and i run into the trouble since i am new to react native and previously i have been manipulating the DOM using querySelector or getElementById functions. However this does not work in react, and i am using state to store the value from the user, but i just can't seem to get it right, What am i doing wrong?
I've inserted the calculation element that is later rendered in app.js. All elements are showing up with no error, but the problem is to get user input data and then be able to use that data and do calculations.
Here is my Class
class LanKalkylElement extends React.Component {
constructor(props) {
super(props);
this.state = {
loanAmount: 20000,
loanInterest: 2.5,
loanYear: 10,
};
}
changeAmount(loanAmount) {
this.setState(() => {
return {
loanAmount: parseFloat(loanAmount),
};
});
}
changeInterest(loanInterest) {
this.setState(() => {
return {
loanInterest: parseFloat(loanInterest),
};
});
}
changeYear(loanYear) {
this.setState(() => {
return {
loanYear: parseFloat(loanYear),
};
});
}
calcButton() {
Alert.alert(this.props.loanAmount);
}
buttonHomeFunc() {
this.props.navigation.navigate('Start');
}
render() {
const {loanAmount, loanInterest, loanYear} = this.state;
return(
<View style={styles.contentStyle}>
<Text style={styles.text}> Lånebelopp </Text>
<TextInput style={styles.numericInput}
onBlur={Keyboard.dismiss}
keyboardType={'numeric'}
value={loanAmount}
onValueChange={this.changeAmount.bind(this)} />
<Text style={styles.text}> Ränta </Text>
<TextInput style={styles.numericInput}
onBlur={Keyboard.dismiss}
keyboardType={'numeric'}
value={loanInterest}
onValueChange={this.changeInterest.bind(this)} />
<Text style={styles.text}> Antal år: {String(loanYear)}</Text>
<Slider step={1}
maximumValue={15}
value={loanYear}
onValueChange={this.changeYear.bind(this)} />
<Button title='Kalkylera' onPress={() => this.calcButton()}/>
<Text style={styles.textResult}>Total summa att återbetala:</Text>
<Text style={styles.textResult}>varav räntekostnad:</Text>
<Button title='Tillbaka' onPress={() => this.buttonHomeFunc()}/>
</View>
)
}
}
export default withNavigation(LanKalkylElement);
When a user changes a value in a text input, onValueChange is called. You have bound this prop to functions that modify the state for this component.
This means the value in the text input will always match the value in the state. Therefore, if you need to access the value in a text input you would simply retrieve it from the state, like this:
const loanAmount = this.state.loanAmount;
doSomethingWithLoanAmount(loanAmount);

props data not being rendered

I'm trying to display some data in a FlatList. the data comes from a json file and is mapped to the component props using redux. I can console.log the props data from inside my component but i cant get to render it on screen. (this.props.library.title). Instead I have an empty list.
I'm following a udemy course and i'm pretty sure i followed the steps exactly
here is my child component :
class ListItem extends Component{
render(){
//const _this = this;
const {title,id}=this.props.library ;
console.log(this.props);
return(
<TouchableWithoutFeedback onPerss={()=> this.props.selectLibrary(id)}>
<View>
<CardSection>
<Text style={styles.textStyle}>
{title}
</Text>
</CardSection>
</View>
</TouchableWithoutFeedback>
);
}
}
const styles ={
textStyle:{
fontSize:18,
padding:5
}
}
export default connect(null,actions)(ListItem);
here is the console log :
https://imgur.com/pd2qbkt
you should put an item after this.props.library
like this
const { title, id } = this.props.library.item

How to bind(this) when passing a function as a prop in react native

I am working on a simple calculator app to learn react native. I have a button component that displays the number buttons. I need to pass it a function so that when the button is touched the state of the parent is updated to the new number.
Without the bind(this) it says this.setState is undefined. When I add bind(this) in the constructor all I get is a blank page in my app. My code is listed below.
constructor:
constructor() {
super();
this.state = {
total: 0,
display: 0
};
this._displayUpdate = this._displayUpdate.bind(this);
}
One row of calculator buttons:
<View style={styles.buttonRow}>
<NumButton numText={7} update={this._displayUpdate} />
<NumButton numText={8} update={this._displayUpdate} />
<NumButton numText={9} update={this._displayUpdate} />
<FuncButton funcText={'*'} />
</View>
NumButton Component:
export default class NumButton extends Component {
render() {
return (
<TouchableHighlight style={styles.buttonArea} onPress={this.props.update(this.props.numText)}>
<Text style={styles.buttonText}>{this.props.numText}</Text>
</TouchableHighlight>
)
}
}
Your parent bind is right. The problem is with the onPress of the TouchableHighlight in the NumButton component. You can't add code to execute to it, You should pass a function to it. You can use ES6 arrow function:
export default class NumButton extends Component {
render() {
return (
<TouchableHighlight style={styles.buttonArea}
onPress={()=>{ this.props.update(this.props.numText) }}
>
<Text style={styles.buttonText}>{this.props.numText}</Text>
</TouchableHighlight>
)
}
}

undefined is not an object(evaluating 'this.props._navigate.replace/push')

I'm new to React Native and trying ( followed a tutorial ) to move to another screen when a button is clicked, this is the updated code I have and a photo of the error I get when pressing the button.
index.ios.js:
export default class Application extends Component {
constructor(){
super();
}
renderScene(route, navigator){
if(route.name == 'login'){
return <Login navigator={navigator}/>
}else if(route.name == 'home'){
return <Home navigator={navigator}/>
}
}
render() {
return <Navigator
initialRoute={{name: 'login'}}
renderScene={this.renderScene.bind(this)}/>
}
}
LoginForm:
export default class LoginForm extends Component{
constructor(props){
super(props);
this.navigate = this.navigate.bind(this);
}
navigate(routeName){
this.props.navigator.replace({
name: routeName,
Component: Home
});
}
render(){
return(
<View style={mStyle.container}>
<StatusBar barStyle='light-content'/>
<TouchableOpacity>
<Text style={mStyle.btnText}>
LOGIN WITH FACEBOOK
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>this.navigate('home')}>
<Text style={mStyle.noLoginTxt}>
CONTINUE WITHOUT LOGIN
</Text>
</TouchableOpacity>
</View>
);
}
}
I'm trying to move from login screen to home screen when button is clicked.
I get this problem when pressing the button on the emulator:
A couple of problems that you are facing.
1.- The syntax is:
this.props.navigator.{any_method}
Such as:
this.props.navigator.push
this.props.navigator.replace
Not
this.props._navigate.{any_method}
2.- If you have child views make sure you are sending to the childs the Navigator property such as.
<View>
<MyChildComponent navigator={this.props.navigator} />
</View>
3.- Make sure your child view gets the props from the parent on the constructor.
Change
constructor(){
super();
this._navigate = this._navigate.bind(this);
}
To
constructor( props ){
super( props );
// The following line is not required since you are using an arrow function to call this one.
// this._navigate = this._navigate.bind(this);
}
It is because there is a mismatch between property you use in Navigator and in your component
Change
_navigate(name){
this.props._navigate.replace({ //I also tried push, same problem.
name
});
}
to
_navigate(name){
this.props.navigator.replace({ //I also tried push, same problem.
name
});
}