How to use React Native Switch inside a functional component? - react-native

I am trying to use the Switch component provided by react-native, but it doesn't toggle.
function settings(props) {
let {changeView, header} = props;
let rememberPin = false;
let toggleRememberPin = (value) => {
rememberPin = value;
};
return (
<View style={styles.appContainer}>
<View style={styles.appBody}>
<View style={{flex:1, flexDirection: 'row',justifyContent:'center',alignItems:'center',width: Dimensions.get('screen').width,backgroundColor: Colors.white}}>
<Text>Remember PIN:</Text>
<Switch
onValueChange={toggleRememberPin}
value={rememberPin}
ios_backgroundColor="#aeaeae"
trackColor={{true: Colors.customerGreen, false: '#aeaeae',}}/>
</View>
</View>
</View>
);
}
I get the Switch rendered in the View, I can touch it and it moves from OFF to ON, but suddently it come back to OFF without keeping on ON state.
What's wrong?

You need to look into the core concepts of React, particularly how component state works.
In short, normal variable assignment doesn't cause a component to re-render and reflect changes. That's when you want to use the concept of state.
Here's how to do it properly:
function Settings(props) {
let {changeView, header} = props;
const [rememberPin, setRememberPin] = useState(false);
const toggleRememberPin = (value) => {
setRememberPin(value);
};
return (
<View style={styles.appContainer}>
<View style={styles.appBody}>
<View style={{flex:1, flexDirection: 'row',justifyContent:'center',alignItems:'center',width: Dimensions.get('screen').width,backgroundColor: Colors.white}}>
<Text>Remember PIN:</Text>
<Switch
onValueChange={toggleRememberPin}
value={rememberPin}
ios_backgroundColor="#aeaeae"
trackColor={{true: Colors.customerGreen, false: '#aeaeae',}}/>
</View>
</View>
</View>
);
}

Related

How to use hooks as image's source in react native?

Im making this menu that when the user clicks at an option, it changes the background image, but i cant use the hook that i created as a parameter to the source of the image. Can someone find where im wrong and how to fix it?
Heres the part of my code referents to the menu and the hooks:
export function Home(){
let imagens = {
vovo: '../assets/vovoJuju.png',
mc: '../assets/mcJuju.png',
pato: '../assets/patoJuju.png',
}
const navigation = useNavigation<any>();
const [showBottomSheet, setShowBottomSheet] = React.useState(false);
const [param, setParam] = useState(1);
const [skin, setSkin] = useState('vovo')
const hide = () => {
setShowBottomSheet(false)
}
function handleAbout(){
navigation.navigate('About');
}
useEffect(() => {
if(param==1){
setSkin('vovo');
}
else if(param==2){
setSkin('mc');
}
else if(param==3){
setSkin('pato');
}
})
return(
<SafeAreaView style={styles.container}>
<TouchableOpacity onPress={handleAbout}>
<Counter />
</TouchableOpacity>
<TouchableOpacity onPress={() => {
setShowBottomSheet(true)
}}
>
<Image source={skin} style={styles.imgvj}/>
</TouchableOpacity>
<BottomSheet show={showBottomSheet} height={290} onOuterClick={hide}>
<Pressable onPress={hide} style={styles.bottomSheetContent}>
<Image source={barrinhaLoja} style={styles.barra}/>
</Pressable>
<View style={styles.conteudoLoja}>
<View style={styles.marginLeft48}>
<TouchableOpacity onPress={() => {
setParam(1);
}}>
<Image source={vovoJuju} style={styles.vovo}/>
<Text style={styles.legendasLoja}>Vovó Juju</Text>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity onPress={() => {
setParam(2);
}}>
<Image source={mcJuju} style={styles.mc}/>
<Text style={styles.legendasLoja}>MC Juju</Text>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity onPress={() => {
setParam(3);
}}>
<Image source={patoJuju} style={styles.pato}/>
<Text style={styles.legendasLoja}>Pato Juju</Text>
</TouchableOpacity>
</View>
</View>
</BottomSheet>
I created the "let imagens", "const param", "const skin" and the "useEffect trying" to make this function. I already tried using the source in different ways such as source={skin} and source={imagens[skin]} but it havent worked.
I'm not certain if this solves your problem, but here's how the first few lines of your component should look like without useEffect:
const imagens = {
vovo: '../assets/vovoJuju.png',
mc: '../assets/mcJuju.png',
pato: '../assets/patoJuju.png',
};
export function Home(){
const navigation = useNavigation<any>();
const [showBottomSheet, setShowBottomSheet] = React.useState(false);
const [param, setParam] = useState(1);
const hide = () => {
setShowBottomSheet(false)
}
function handleAbout(){
navigation.navigate('About');
}
let skin = 'vovo';
switch(param) {
case 1: skin = 'vovo'; break;
case 2: skin = 'mc'; break;
case 3: skin = 'pato'; break;
}
return /* the rest goes here */
}
To reference the actual image, you would use something like {imagens[skin]}.
I moved imagens outside of this function because it never changes, but it doesn't impact anything otherwise.

Updating button state which is clicked, inside RenderItem of Flat-list, in React Native

I am new to React Native and trying to accomplish something like below, where simple list from server is rendering in a list with a button. Button, upon click, will be disabled and opacity will be changed.
I am able to create the UI but when I click any button that says Join, previous clicked button resets it state to original. In other words, only one button displays clicked state all the time.
so my code is something like
constructor(props){
super(props);
this.state = {selectedIndices: false, groupsData: ''};
}
Flatlist inside render method looks like
<FlatList style={styles.list}
data={this.state.groupsData}
keyExtractor={(groups) => {
return groups.groupId.toString();
}}
renderItem={(item, index) => {
return this.renderGroupItem(item);
}}/>
RenderGroupItem
renderGroupItem = ({item} )=>(
<GroupItem group = {item} style={{height: '10%'}} onPress = {() => this.onJoinButtonPress(item)}
index = {this.state.selectedIndices}/>
)
onJoinButtonPress
onJoinButtonPress = (item) =>{
this.setState({selectedIndices: true});
}
GroupItem
render(){
if(this.props.group.groupId === this.props.index){
return(
<View style = {[styles.container]}>
<Image source={{uri: 'some Image Url'}} style={styles.roundImage}/>
<Text style={styles.groupText}>{this.props.group.name}</Text>
<View >
<TouchableOpacity style = {[styles.button, {opacity: 0.4}]} activeOpacity = { .5 } onPress = {this.props.onPress}
disabled = {true}>
<Text style = {{color: 'white', fontSize: 12}}>Joined</Text>
</TouchableOpacity>
</View>
</View>
);
}else{
return(
<View style = {styles.container}>
<Image source={{uri: 'Some Image Url'}} style={styles.roundImage}/>
<Text style={styles.groupText}>{this.props.group.name}</Text>
<View >
<TouchableOpacity style = {styles.button} activeOpacity = { .5 } onPress = {this.props.onPress}>
<Text style = {{color: 'white', fontSize: 12}}>Join</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
Now I know that I need to pass an array or hasmap which contains mapping of items that have been clicked but I dont know how to do that. Need desperate help here.
I was able to overcome above problem after maintaining a boolean in the groupsData. Upon selection, I update a boolean "groupsJoined" in groupsData and update the state of groupsData which will invoke render. Inside GroupsItem class, I added a check that if data from props has joinedGroups as true then render selected state else non selected state.
Courtesy https://hackernoon.com/how-to-highlight-and-multi-select-items-in-a-flatlist-component-react-native-1ca416dec4bc

Switch button in react-native

Hi I have a problem with the switch button in react-native. I'm using it to toggle or not the activation of push notification. The problem is that if I quit the application, the state of the switch is getting back to false, it's not saving the state ? What am I doing wrong ?
Here is my code :
constructor(props) {
super(props)
this.state = {
switchValue:false
}
}
toggleSwitch = (value) => {
this.setState({switchValue: value})
if(this.state.switchValue){
console.log("Unsubscribed")
} else {
console.log("Subscribed")
}
}
render() {
return (
<SafeAreaView>
<ScrollView>
<View style = {styles.view_container}>
<Text style = {styles.titre}>Notifications</Text>
<Text style = {{marginTop:9}}>Permet de recevoir des alertes lorsque de nouvelles vidéos sont disponibles.</Text>
<View style = {{marginTop: 30, justifyContent:"center", alignContent:"center"}}>
<View style = {styles.row}>
<View style = {styles.row_infos}>
<Image source={require('../Images/couleurs/icons8-belier-100.png')} style = {styles.image}/>
<Text style = {{fontWeight:"bold", fontSize:16,lineHeight:16, color:"#7c4dff"}}>Bélier</Text>
</View>
<Switch
onValueChange = {this.toggleSwitchBelier}
value = {this.state.switchValueBelier}
trackColor={{false:'#000000', true:'#7c4dff'}}
/>
</View>
</View>
</View>
</ScrollView>
</SafeAreaView>
)}
When you quit your Application, all saved variables in the state will be "resetted".
If you would like to keep the state of the toggle button, i would recommend you to use the AsyncStorage, provided by expo.
See here:
https://docs.expo.io/versions/v36.0.0/react-native/asyncstorage/
Just set the item when the toggle-function is triggered like this:
import { AsyncStorage } from 'react-native';
AsyncStorage.setItem('buttonToggle', 'true');
And when you start the application again, load the current status from the AsyncStorage:
const value = await AsyncStorage.getItem('buttonToggle');
if (!!value && value === 'true'){
// Do whatever you like
}

pass multiple props by react navigation

I am new to react-native and trying to make a GSTCalculator App. I take values from the user on calculator screen and show calculated values on Result screen. My problem is that the calculated values don't show up immediately on the Result screen. I have even used async and await. But it only shows first calculated value.
calculate = async() => {
await this.calculateSum();
this.props.navigation.navigate('Result', {prodCost: this.state.prodCost,
mfdProfitMargin: this.state.mfdProfitMargin, mCost: this.state.mCost, whProfit: this.state.whProfit,
rtProfit: this.state.rtProfit, cgst: this.state.cgst, sgst: this.state.sgst, igst: this.state.igst,
igstV: this.state.igstV, m2wV: this.state.m2wV, w2rT: this.state.w2rT, whProfitV: this.state.whProfitV,
cgstV: this.state.cgstV, sgstV: this.state.sgstV, w2rV :this.state.w2rV, rtProfitV: this.state.rtProfitV })
}
calculateSum = () => {
this.setState({mCost: Number(this.state.prodCost) + Number(this.state.mfdProfitMargin)});
this.setState({igstV: (Number(this.state.mCost)*Number(this.state.igst))/100});
this.setState({m2wV: Number(this.state.mCost) + Number(this.state.igstV)});
this.setState({whProfitV: (this.state.m2wV)*Number(this.state.whProfit)/100});
this.setState({w2rT: Number(this.state.m2wV) + Number(this.state.whProfitV)});
this.setState({cgstV: (this.state.w2rT)*Number(this.state.cgst)/100});
this.setState({sgstV: (this.state.w2rT)*Number(this.state.sgst)/100});
this.setState({w2rV: Number(this.state.w2rT) + Number(this.state.cgstV) + Number(this.state.sgstV)});
this.setState({rtProfitV: (this.state.w2rV)*Number(this.state.rtProfit)/100});
}
export default class Result extends Component {
constructor(props) {
super(props);
this.state = { pCost: this.props.navigation.state.params.prodCost, pMargin: this.props.navigation.state.params.mfdProfitMargin,
mCost:this.props.navigation.state.params.mCost, igstP: this.props.navigation.state.params.igst,
igstV: this.props.navigation.state.params.igstV, cgstP: this.props.navigation.state.params.cgst,
cgstV: this.props.navigation.state.params.cgstV, sgstP: this.props.navigation.state.params.sgst,
sgstV: this.props.navigation.state.params.sgstV, m2wV: this.props.navigation.state.params.m2wV,
whProfit: this.props.navigation.state.params.whProfit, whProfitV: this.props.navigation.state.params.whProfitV,
w2rT: this.props.navigation.state.params.w2rT, w2rV: this.props.navigation.state.params.w2rV,
rtProfit:this.props.navigation.state.params.rtProfit, rtProfitV: this.props.navigation.state.params.rtProfitV
}
}
render() {
return(
<View>
<ImageBackground source={require('../Assets/login.jpg')} style={Styles.bgImage}>
<ScrollView contentContainerStyle={GStyle.container}>
<View>
<Text style={[Styles.heading, {marginTop: 20}]}>Manufacturer to Wholesaler:</Text>
<View style={GStyle.inputView}>
<Text style={[GStyle.text, {marginTop:10}]}>Production Cost</Text>
<Text style={GStyle.resultText}>{this.state.pCost}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Profit Margin</Text>
<Text style={GStyle.resultText}>{this.state.pMargin}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Manufacture Cost</Text>
<Text style={GStyle.resultText}>{this.state.mCost}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>IGST({this.state.igstP}%)</Text>
<Text style={GStyle.resultText}>{this.state.igstV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Invoice Value</Text>
<Text style={GStyle.resultText}>{this.state.m2wV}</Text>
</View>
</View>
<View>
<Text style={[Styles.heading, {marginTop: 20}]}>Wholesaler to Retailer:</Text>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Cost to Wholesaler</Text>
<Text style={GStyle.resultText}>{this.state.m2wV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Profit Margin({this.state.whProfit}%)</Text>
<Text style={GStyle.resultText}>{this.state.whProfitV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Total</Text>
<Text style={GStyle.resultText}>{this.state.w2rT}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>CGST({this.state.cgstP}%)</Text>
<Text style={GStyle.resultText}>{this.state.cgstV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>SGST({this.state.sgstP}%)</Text>
<Text style={GStyle.resultText}>{this.state.sgstV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Invoice Value</Text>
<Text style={GStyle.resultText}>{this.state.w2rV}</Text>
</View>
</View>
<View>
<Text style={[Styles.heading, {marginTop: 20}]}>Retailer to Consumer:</Text>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>Cost to Retailer</Text>
<Text style={GStyle.resultText}>{this.state.w2rV}</Text>
</View>
<View style={GStyle.inputView}>
<Text style={GStyle.text}>ProfitMargin({this.state.rtProfit}%)</Text>
<Text style={GStyle.resultText}>{this.state.rtProfitV}</Text>
</View>
</View>
</ScrollView>
</ImageBackground>
</View>
);
}
}
There is a lot of setting of state going I think we can reduce it and there is a little refactoring we can do to make your code easier to read.
Constructor
You are typing the same thing over and over again and it makes your constructor much harder to read than it needs to be.
In this example we have taken the the value this.props.navigation.state.params and set it to it's own variable. This means you don't have to keep typing the this.props.navigation.state.params over and over and over again.
constructor(props) {
super(props);
const params = this.props.navigation.state.params
this.state = {
pCost: params.prodCost,
pMargin: params.mfdProfitMargin,
mCost:params.mCost,
igstP: params.igst,
igstV: params.igstV,
cgstP: params.cgst,
cgstV: params.cgstV,
sgstP: params.sgst,
sgstV: params.sgstV,
m2wV: params.m2wV,
whProfit: params.whProfit,
whProfitV: params.whProfitV,
w2rT: params.w2rT,
w2rV: params.w2rV,
rtProfit:params.rtProfit,
rtProfitV: params.rtProfitV
}
}
If we use spread operator we can make this even easier, that is if you are willing to use the same name as in the object that you are passing.
constructor(props) {
super(props);
this.state = {
...this.props.navigation.state.params
}
}
However, if you use this method then you will find that some of the unique names you have chosen will be gone, replaced by the ones that are in the object that you are passing.
I am assuming that you would go with the first option (as it doesn't change the names) so I will base my next refactors on that.
Calculate Sum
There are too many setStates here, It takes time for state to set, so you could be using old values in your subsequent calculations so it is best not to use setState until you have performed all your calculations. If the values for each setState depend on the previous values then you could do something like this, only using values from the initial state where necessary.
calculateSum () => {
let mCost = Number(this.state.prodCost) + Number(this.state.mfdProfitMargin);
let igstV = mCost * Number(this.state.igst) / 100;
let m2wV = mCost + igstV;
let whProfitV = m2wV * Number(this.state.whProfit)/100;
let w2rT = m2wV + whProfitV;
let cgstV = w2rT * Number(this.state.cgst)/100;
let sgstV = w2rT * Number(this.state.sgst)/100;
let w2rV = w2rT + cgstV + sgstV;
let rtProfitV = w2rV * Number(this.state.rtProfit)/100;
return { mCost, igstV, m2wV, whProfitV, w2rT, cgstV, sgstV, w2rV, rtProfitV }
}
Here I return an object with all the updated values, that can be saved to state if we so choose.
Calculate
As the calculateSum function now returns an object with all the value that you want you could do something like this. We take the sum object that we just calculated and using a spread operator set all those objects to state. We then use a callback on the setState function to then navigate to the next page, using the spread operator again to capture all the values that in state.
calculate = () => {
let sum = this.calculateSum();
this.setState({...sum}, () => {
this.props.navigation.navigate('Result', {...this.state })
});
}
However if these values don't need to saved to state and just passed to the next screen, we could update the calculate function to something like this
calculate = () => {
let sum = this.calculateSum();
this.props.navigation.navigate('Result', {...this.state, ...sum })
}
I hope this helps you.
For more information on the spread operator in javascript see this article
https://zendev.com/2018/05/09/understanding-spread-operator-in-javascript.html
For more information on setting state check out both of these articles
https://medium.learnreact.com/setstate-is-asynchronous-52ead919a3f0
https://medium.learnreact.com/setstate-takes-a-callback-1f71ad5d2296

How to get the style name and state name of a clicked element in React Native?

In the following, first example how do I check if the clickable element TouchableWithoutFeedback has the style named EntryBlock1?
render() {
return (
<TouchableWithoutFeedback style={styles.EntryBlock1} onPress={() => this.CheckIfHasStyles()}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback style={styles.EntryBlock2} onPress={() => this.CheckIfHasStyle()}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
); // end return
} // end render
In the 2nd example, how can I check if TouchableWithoutFeedback has the state name EntryBlock1 ?
constructor (props) {
super(props);
this.state = {
EntryBlock1: [styles.entryBlockButton, styles.entryBlockButtonMin],
EntryBlock2: [styles.entryBlockButton, styles.entryBlockButtonMax],
}
}
render() {
return (
<TouchableWithoutFeedback style={this.state.EntryBlock1} onPress={() => this.CheckIfHasStateName()}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
); // end return
What I've Tried
Different stuff along the lines of the following..
CheckIfHasStyles =()=> {
var object = this.state;
var stringifiedObject = JSON.stringify(object);
var slicedObject = stringifiedObject.slice(2, 13);
if (slicedObject === 'EntryBlock1') {
alert('success');
} else {
alert('failure');
}
}
.. which actually works for one very specific example, but not when I have multiple state names as this.state gets all of them in one object and not just the state of the element clicked.
Note: My question is solely about getting attributes and their values. It is to help me develop a style of toggling styles on elements but I am only looking for attribute stuff in these answers as I would like to use attributes, if possible, for more than just toggling in the future.
You can pass it as parameter to your function directly like this:
render() {
return (
<TouchableWithoutFeedback style={styles.EntryBlock1} onPress={() => this.CheckIfHasStyles('EntryBlock1')}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback style={styles.EntryBlock2} onPress={() => this.CheckIfHasStyle('EntryBlock2')}>
<View style={styles.redundantWrapperNumber1}>
<Text style={styles.redundantWrapperNumber2}>Click To Test For Style</Text>
</View>
</TouchableWithoutFeedback>
);
}
and check if you are receiving any parameter in your function and do what you want
based on If-else condition