Call a function once onPress then display other function - react-native

I'm doing a react-native school project and i'm willing to know how to call a function on first press then display another function on other clicks :
<TouchableOpacity style={styles.btnMiddle} onPress={() => buyFishes(1)}>
<View style={styles.fish}>
<Text style={styles.shptxt}>50</Text>
<Image style={styles.coin2}source={require("../../assets/img/coin.png")} />
</View>
</TouchableOpacity>
here is my button, in my project this button is displayed on the Shop Screen and I need it to cost 50 on the first press (to unlock it), then I want it to stop costing 50 and just call another function.
here is my function to buy an item
const buyFishes = (id) => {
fishes.map(fishes => {
if(fishes.id === id)
{
if(Gold >= fishes.cost)
{
setGold(Gold - fishes.cost);
}
}
if (Gold < fishes.cost)
{
onPress: () => Alert.alert("Not enough Gold Kiddo !");
}
}
);
};
Any Idea ?
Thanks

Just add a state to your component and use it to call the functions you want accordingly.
const [clicked,setClicked] = useState(false);
<TouchableOpacity style={styles.btnMiddle} onPress={onPressHandler}>
<View style={styles.fish}>
<Text style={styles.shptxt}>50</Text>
<Image style={styles.coin2}source={require("../../assets/img/coin.png")} />
</View>
</TouchableOpacity>
const onPressHandler = (id) => {
setClicked(true);
if(clicked)
{
// call second function
}
else
{
// call first function
}
};

Related

how do i get a value picked from another screen?

im using navigation to pass between screens.
now,im trying to figure out how can i get a value from second screen to the first screen ?
the user needs to pick a color value from the second screen and return selcted color to the first screen.
this is the code im using .
enter code here
<CustomButton
style={styles.buttonPicker}
darkMode={this.props.darkMode}
title={'pick a color'}
onPress={() => {
this.props.navigation.navigate('ColorPickerScreen', {
onSubmit: (namecolor) => {
console.log('55555555555555', { getNameColor })
},
})
}}
></CustomButton>
enter code here
onSelect = (color) => this.props.navigation.navigate('CreatenewtTipul')
render() {
return (
<Image
style={styles.img}
source={require('../components/icons/color-wheel.png')}
/>
<ColorPicker
colors={this.state.colors}
selectedColor={this.state.selectedColor}
onSelect={this.onSelect}
/>
<Text>Selected Color = {this.state.selectedColor}</Text>
</View>
)
}
}
tnx for any help
arik :)
To pass value from screen A to screen B:
navigation.navigate('ScreenB', {
itemId: 86,
otherParam: 'anything you want here',
});
To access that value in Screen A:
const { itemId, otherParam } = route.params;
Where were route here is part of the screen's props, check the guide here for more info
im not trying to pass a value to the second screen.
im trying to get a value from the second screen to the first screen.
You can pass a function as a callback from the first screen to the second screen in params on call that on your second screen.
function Screen1(props) {
const onSelect = (selectedColor) => {
console.log('selectedColor', selectedColor)
}
const navigateToSecondScreen = () => {
props.navigation.navigate('Screen2', {
onColorSelect: onSelect
})
}
return(
<View>
<TouchableOpacity onPress={navigateToSecondScreen}>
<Text>Go to second screen</Text>
</TouchableOpacity>
</View>
)
}
//Second Screen
function Screen2(props) {
const {onColorSelect} = props.route.params;
return(
<View>
<TouchableOpacity onPress={() => {onColorSelect('color value')}}>
<Text>your other code here</Text>
</TouchableOpacity>
</View>
)
}
The idea is just to call the function which you have passed as a param from Screen1

Calling modal on a list of products opens the modal for all of them instead of just the one being clciked

I am making a react native app that loads data from google firebase and then display it on a page, when a user clicks on any of the products aa modal will open to show more datails.
I am using useEffect to load the data on page load then display then results:
const fetchData = async () => {
const categories = db.collection("productsDB");
const collections = await categories
.limit(6)
.onSnapshot((querySnapshot) => {
const items = [];
querySnapshot.forEach((documentSnapshot) => {
items.push({
...documentSnapshot.data(),
key: documentSnapshot.id,
});
});
setItems(items);
setLoading(false);
});
return () => collections();
};
useEffect(() => {
fetchData();
}, []);
and the show them like this:
{loading ? (
<ActivityIndicator />
) : (
items.map((item) => (
<TouchableOpacity
style={styles.queryResult}
key={item.key}
onPress={() => {
setModalVisible(!modalVisible);
}}
>
<View style={styles.queryResultContent}>
<Image
style={{ width: 100, height: 100 }}
source={{ uri: String(item.images) }}
/>
<View>
<Text style={styles.queryInfoHeader}>{item.name}</Text>
</View>
</View>
<View>
<ProductModal
isModalVisible={modalVisible}
setModalVisible={setModalVisible}
navigation={navigation}
{...item}
/>
</View>
</TouchableOpacity>
))
)}
when I open the modal, it opens the modal for all of the products and doesnt really matter if I click on the first product or what, it opens all of the modals, and I am not sure how to get rid of this!
is there any better way to write this function?
You're using the same modalVisible flag for all of your modals; therefore, they either are all visible or all hidden.
Why not have a single modal rather than rendering a bunch of them in the loop, and pass the item as a prop to it?

How to change state with useState hook using a variable

I have a FlatList with about 60 items.
Each item has a small button that is clicked to display more information inside the FlatList item.
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo() }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo ? <View><Text>{ itemData.item.info }</Text><View> : null }
The onPress toggle function is something like:
const toggleInfo = () => {
if (showInfo === true) {
setShowInfo(false);
} else {
setShowInfo(true);
}
};
Of course, since it's a FlatList, when I click the button all of the FlatList items show their hidden contents. But I only want the info for the clicked item to show, leaving all the others unchanged.
So, I changed the onPress to take an argument:
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
...which is fine. But now I need to target the right state array (which is the same as the id but with an "z" tacked on the end to avoid any variable conflicts):
const toggleInfo =(id) => { // id might be "ABC"
const infoState = `${id}z`;
const infoStateSET = `set${speciesState}`; // therefore: setABCz
// Now I want to target the state "ABCz" and "setABCz" useState variables
if (infoState === true) {
infoStateSET(false);
} else {
infoStateSET(true);
}
};
Now, obviously there is no literal "infoStateSET" to change the state but I do want to use the variable to target the set state function.
Is this possible?
You can just set the id in showInfo state and then check if showInfo id is the same as the itemData.item.id.
basically you would have a state like this.
const [showInfo, setShowInfo] = useState(null);
Then you would set the state like so using your toggleInfo function:
const toggleInfo = (id) => {
if (showInfo === id) {
setShowInfo(id);
} else {
setShowInfo(null);
}
}
Then in your Flatlist item:
<View style={styles.infoIcon} >
<TouchableOpacity onPress={() => { toggleInfo(itemData.item.id) }} >
<Ionicons name="ios-information-circle" size={40} color={"#0ca9dd"} />
</TouchableOpacity >
</View>
{showInfo === itemData.item.id ? <View><Text>{ itemData.item.info }</Text><View> : null }

React native updates state "on its own"

I have two screens, one list (Flatlist) and one filter screen where I want to be able to set some filters for the list. the list screen has the states "data" and "usedFilters". When I am switching to the filters screen, the states are set as navigation parameters for react navigation and then passed via navigation.navigate, together with the onChange function, as props to the filter screen. There they are read, and the filters screen class' state is set (usually with passed filters from the list screen, if no valid filters has been passed, some are initialized).
After that the filters can be changed. If that happens, the state of the filter screen gets updated.
If then the apply button is clicked the filter screens' state is passed to the onChange function and via that back to the list screen, the onChange function updates the state "usedFilters" state of the list screen. If the cancel button is pressed null is passed to the onChange function and there is no setState call.
Setting new states for the list screen works perfectly fine. the problem is, that when i press the cancel button (or the back button automatically rendered by react navigation) the changes are kept nevertheless. That only happens if the state has been changed before. So if there has never been applied a change and hence the "usedFitlers" state of the list screen is null, this behavior does not occur. Only if I already made some changes and hence the "usedFitlers" state of the list screen has a valid value which is passed to the filters screen the cancel or go back buttons won't work as expected.
I am using expo-cli 3 and tried on my android smartphone as well as the iOS simulator. Same behavior. I looked into it with chrome dev tools as well but i simply couldn't figure out where the "usedFitlers" state was updated.
I am using react native 0.60 and react navigation 3.11.0
My best guess is that for some reason the two states share the same memory or one is pointer to the other or sth like that. (Had problems like that with python some time ago, not knowing the it uses pointers when assigning variables).
Anyone got an idea?
List Screen:
export default class ListScreen extends React.Component {
state = { data: [], usedFilters: null };
static navigationOptions = ({ navigation }) => {
let data = navigation.getParam('data')
let changefilter = navigation.getParam('changeFilter')
let currfilter = navigation.getParam('currFilter')
return {
headerTitle:
<Text style={Styles.headerTitle}>{strings('List')}</Text>,
headerRight: (
<TouchableOpacity
onPress={() => navigation.navigate('FilterScreen', {
dataset: data, onChange: changefilter, activeFilters:
currfilter })} >
<View paddingRight={16}>
<Icon name="settings" size={24} color=
{Colors.headerTintColor} />
</View>
</TouchableOpacity>
),
};
};
_onChangeFilter = (newFilter) => {
if (newFilter) {
this.setState({ usedFilters: newFilter })
this.props.navigation.setParams({ currFilter: newFilter });
} // added for debugging reasons
else {
this.forceUpdate();
let a = this.state.usedFilters;
}
}
_fetchData() {
this.setState({ data: fakedata.results },
() => this.props.navigation.setParams({ data: fakedata.results,
changeFilter: this._onChangeFilter }));
}
componentDidMount() {
this._fetchData();
}
render() {
return (
<ScrollView>
<FlatList/>
// Just data rendering, no problems here
</ScrollView>
);
}
}
Filter Screen:
export default class FilterScreen extends React.Component {
static navigationOptions = () => {
return {
headerTitle: <Text style={Styles.headerTitle}> {strings('filter')}
</Text>
};
};
state = { currentFilters: null }
_onChange = (filter, idx) => {
let tmp = this.state.currentFilters;
tmp[idx] = filter;
this.setState({ currentFilters: tmp })
}
_initFilterElems() {
const filters = this.props.navigation.getParam('activeFilters');
const dataset = this.props.navigation.getParam('dataset');
let filterA = [];
let filterB = [];
let filterC = [];
if (filters) {
// so some checks
} else {
// init filters
}
const filterElements = [filterA, filterB, filterC];
this.setState({ currentFilters: filterElements })
}
componentDidMount() {
this._initFilterElems()
}
render() {
const onChange = this.props.navigation.getParam('onChange');
return (
<ScrollView style={Styles.screenView}>
<FlatList
data={this.state.currentFilters} // Listeneinträge
keyExtractor={(item, index) => 'key' + index}
renderItem={({ item, index }) => (
<FilterCategory filter={item} name={filterNames[index]}
idx={index} onChange={this._onChange} />
)}
ItemSeparatorComponent={() => <View style=
{Styles.listSeperator} />}
/>
<View style={Layout.twoHorizontalButtons}>
<TouchableOpacity onPress={() => {
onChange(this.state.currentFilters);
this.setState({ currentFilters: null });
this.props.navigation.goBack();
}}>
<View style={Styles.smallButton}>
<Text style={Styles.buttonText}>{strings('apply')} </Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
onChange(null);
this.setState({ currentFilters: null });
this.props.navigation.goBack();
}}>
<View style={Styles.smallButton}>
<Text style={Styles.buttonText}>{strings('cancel')}
</Text>
</View>
</TouchableOpacity>
</View>
</ScrollView >
);
}
}
So when I press the cancel button, null is returned to the _onChangeFilter function of the list screen. This part works, and according to console.log and the debugger, the setState is not called. But if i set a breakpoint within the else part, i can see that this.state.usedFilters has changed.
Ok after a while i figured it out. The problem was that the whole filters list was always just referenced since react native (js) seems to always use references, even when changing sub-parts of the lists.
fixed that by using lodash cloneDeep.

How to get value on button click in array react native

Hello please help me to sort out from this error.
btnDynamic()
{
return myArr.map(function(data,index){
return(
<TouchableHighlight key={index} onPress={()=> this.btnCLick()} style={styles.btn} underlayColor='transparent'>
<View style={{alignItems:'center',justifyContent:'center'}}>
<Text ref={index} style={{fontSize:6,fontWeight:'bold'}}>{data.category}</Text>
</View>
</TouchableHighlight>
)
});
}
above is my function which gives multiple buttons depend on my another function gives response.
but main problem is button click method gives an error like this.
"this.btnCLick is not a function.(in _this3.btnCLick()),this3.btnClick" is undefine.
this is my btn Click function
btnCLick(text){
Alert.alert("Button Is Clicked",text);
}
please guys help me to solve this error.
Thanks in advance.
I would like to share how to get value on button click array react native
const OpenGallery = () => {
return this.state.photos.map((p, i) => {
let selectImage = p.node.image.uri;
return (
<TouchableOpacity
key={i}
onPress={this.selectImage.bind(this, selectImage)}
>
<Thumbnail
square
style={{
width: 120,
height: 120,
margin: 3
}}
source={{ uri: p.node.image.uri }}
/>
</TouchableOpacity>
);
});
};
Create funtion
selectImage = image => {
const { navigation } = this.props;
this.setState({
isGallery: !this.state.isGallery
});
this.selectedImage = image;
};
According to this concept I can access current array value through button click event.
I hope it will help you.