Use same onPress handle with multiple TouchableOpacity - javascript

I am using a GridView to show multiple products and on click i want to go to details screen , however I am unable to find a way to identify which product grid view cell was selected / tapped by user , I think sending some parameter to handle method should do the trick.
return (
<GridView
itemDimension={130}
items={this.state.dataSource}
style={styles.gridView}
renderItem={item => (
<View style={styles.itemContainer}>
<TouchableOpacity onPress={ this.onPressStone } style={styles.itemContainer}>
<Image source = {{uri:item.url}} style={styles.imageView} />
<Text style={styles.itemName}>{item.name}</Text>
</TouchableOpacity>
</View>
)}
/>
);

You can send parameters to your function like you said.
Example
onPress={ () => this.onPressStone(item.id) }

You can pass to the method onPressStone the item and depending the item you could do that print what you want. And if you want to know who was pressed you just have to make a log with the name of the item or take the index for example
return (
<GridView
itemDimension={130}
items={this.state.dataSource}
style={styles.gridView}
renderItem={(item, index) => {
//to know who was pressed:
console.log('pressedItemName-->', item.name);
//to know index pressed:
console.log('pressedItemName-->', item);
return (
<View style={styles.itemContainer}>
<TouchableOpacity onPress={ ()=> {this.onPressStone(item)} } style={styles.itemContainer}>
<Image source = {{uri:item.url}} style={styles.imageView} />
<Text style={styles.itemName}>{item.name}</Text>
</TouchableOpacity>
</View>
)}
/>
);

Related

How to reference button in card component in React Native?

I'm a newbie to React/React Native, so please go easy on me. I've been stuck on this for a little while now so could use some help. Using functional React Native by the way.
How do I reference buttons that are in a card component from another screen? Using props in the card to display the toilet object's variables isn't a problem, but the buttons that are rendered through the card I can't work out how to reference them from the component with the map. Using navigation within the card doesn't work.
Screen that I want to reference the button in
{toilets.map((item, index) => {
return (
<ToiletCard
key={index}
title ={item.title}
address={item.address}
ratings={item.rating}
reviews={item.reviews}
onPress={() => {navigation.navigate("ReviewViewAndCreate", item)}}
/* I want to reference the review button using this onPress, but right now it isn't
referencing either button /*
/>
)
})}
Card component that contains the buttons
export default ToiletCard = (props) => {
return (
<View style = {styles.textContent}>
<View style = {{padding: 15}}>
<Text numberOfLine={1} style = {styles.listTitle}>{props.title}</Text>
<Text numberOfLine={1} style = {styles.listAddress}>{props.address}</Text>
<Text><StarRating ratings={props.ratings}/>{props.ratings}</Text>
<TouchableOpacity
style={styles.appButtonContainer}>
<Text style={styles.appButtonText}>Directions</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.appButtonContainerTwo}>
<Text style={styles.appButtonText}>Reviews</Text>
</TouchableOpacity>
</View>
<View style={styles.hairline}/>
</View>
)
}
Would appreciate any help.
Thanks!
Do these changes:
{toilets.map((item, index) => {
return (
<ToiletCard
key={index}
title ={item.title}
address={item.address}
ratings={item.rating}
reviews={item.reviews}
item={item}
navigation={navigation}
/* pass item as prop to this component /*
/>
)
})}
ToiletCard component:
export default ToiletCard = (props) => {
return (
<View style = {styles.textContent}>
<View style = {{padding: 15}}>
<Text numberOfLine={1} style = {styles.listTitle}>{props.title}</Text>
<Text numberOfLine={1} style = {styles.listAddress}>{props.address}</Text>
<Text><StarRating ratings={props.ratings}/>{props.ratings}</Text>
<TouchableOpacity
style={styles.appButtonContainer}>
<Text style={styles.appButtonText}>Directions</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={() => {props.navigation.navigate("ReviewViewAndCreate", props.item)}}
style={styles.appButtonContainerTwo}>
<Text style={styles.appButtonText}>Reviews</Text>
</TouchableOpacity>
</View>
<View style={styles.hairline}/>
</View>
)
}

Custom pagination with ScrollView in React Native

In my app i'm using ScrollView for showing images. Below my ScrollViewcomponent i have two buttons like prev and next. I want to add custom pagination with the buttons. Also my images are coming from an array in a loop. I want 4 images to show at a time. So, the next button should show next 4 images if there are any and prev button should take 4 previous images if there are any. My ScrollView is currently like this:
<View>
<View style={{width:width,paddingHorizontal:10,paddingVertical:20}}>
<ScrollView
horizontal={true}
showsHorizontalScrollIndicator={false} >
{list.map((item, i)=>(
<Image key={i} source={{uri: item}}
style={{width: 80, height: 80,marginLeft:5}} />
)
)}
</ScrollView>
</View>
</View>
Below this i have two buttons.I have created two different fuctions for those. Here's what it's like now:
<View>
<Button
title="Prev"
color="#841584"
onPress={handleClickBackward}
/>
</View>
<View>
<Button
title="Next"
color="#841584"
onPress={handleClickForward}
/>
</View>
How can i manipulate with my list array so that the custom pagination works. I have tried array slice method on next but it removes the first images and i don't find those after pressing prev button.
you can use onNextPress function and add ref in scrolview
const scrollRef = useRef<ScrollView>();
const onNextPress = () => {
scrollRef.current?.scrollTo({
y : 0,//you must increase x or y
animated : true
});
}
return (
<View style={{width:width,paddingHorizontal:10,paddingVertical:20}}>
<ScrollView
ref={scrollRef}//ref
horizontal={true}
showsHorizontalScrollIndicator={false} >
{list.map((item, i)=>(
<Image key={i} source={{uri: item}}
style={{width: 80, height: 80,marginLeft:5}} />
)
)}
</ScrollView>
</View>
);

Render via map instead of for loop

I am currently using this function to render some elements & display results after a graphql query:
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
if (data) {
for (var i = 0; i < numberOfUsers; i++) {
const userName = data.users.nodes[i].firstName
.concat(' ')
.concat(data.users.nodes[i].lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(data.users.nodes[i].id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>
</View>
);
}
}
},
[createUserRelationMutation, userData, numberOfUsers],
);
I have read that using a for loop isn't a good idea. Hence, I am trying to switch to a map but I am unable to. I couldn't figure out how to use variables like const userNamewhile using a map.
Currently, I can only test with numberOfUsers = 1so it works fine but in reality, I want all of the item contained in the Viewwhich is styled as friends. For now, there will be a separate <View style={styles.friends}>for each item. However, I want to map all items inside one single <View style={styles.friends}>
Map takes a function as its argument, which means that you can use that same code from the for loop inside of the function passed to the map, like this:
data.users.map((user) => {
const userName = user.firstName
.concat(' ')
.concat(user.lastName);
return (
<View style={styles.friends}>
<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(user.id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>
</View>
);
}
Just replace all instances of data.users.nodes[i] with user since that's what each object in the array is passed into the function as.
For more info about this, check this part of the React docs.
If you want everything to be contained inside the view styled as friends this is how the code should be.
You should have the map inside the view as JS code and access properties from the item variable.
const showUsers = React.useCallback(
(data: UsersLazyQueryHookResult, numberOfUsers: Number) => {
if (data) {
return (
<View style={styles.friends}>
{
data.users.nodes.map(item => {
const userName = item.firstName
.concat(' ')
.concat(item.lastName);
return (<View style={styles.item}>
<Text style={styles.userName}>{userName}</Text>
<View style={styles.addButtonContainer}>
<Button
rounded
onPress={() => {
addFriend(Number(item.id));
setIsSubmitted(false);
setUserData(null);
}}>
<Icon name="plus" size={moderateScale(20)} color="black" />
</Button>
</View>
</View>);
})
}
</View>
);
}
},
[createUserRelationMutation, userData, numberOfUsers],
);

Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of 'search'

The search is perfect and it's all looks fine, but gets this warning.
I get this warning when I press any key to start the search method.
"Song_ID", "Song_Name" and "Image" are of the variable names from the SQL Database.
- I looked on other question as this, but it didn't help me at all.
This is the code where the error is :
return (
<View>
<ScrollView>
{musicList.map(songObj => {
return (
<View style={styles.resultsContainer}> /// Its written that the erorr in this line
<TouchableOpacity onPress={this.GetListViewItem.bind(this, songObj.Song_Name)}>
<Text style={{ fontSize: 16 }} key={songObj.Song_ID}>
{songObj.Song_Name}</Text>
<Image source={{ uri: songObj.Image }} style={styles.img} />
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</View>
);
}
I don't understand where to put the key and/or what does it mean, I tried so many times but it didn't went well.
If more details is needed please tell me and I'll insert the right code.
You should add the key onto the outermost component inside the map. In your case, this is the View. Try this:
return (
<View>
<ScrollView>
{musicList.map(songObj => {
return (
<View style={styles.resultsContainer} key={songObj.Song_ID}>
<TouchableOpacity onPress={this.GetListViewItem.bind(this, songObj.Song_Name)}>
<Text style={{ fontSize: 16 }}>
{songObj.Song_Name}</Text>
<Image source={{ uri: songObj.Image }} style={styles.img} />
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</View>
);
}
Adding the key prop lets react optimize rendering which is why it recommends you add it. Read the docs for more info.

React Native : How to call child refs from the parent's event funtion?

Have parent tag as <TouchableWithoutFeedback> and child as <Image>, trying to change the image source from the parent onPress function, but getting error. how can I archive this using refs? or any other way to resolve it?
React-native version : 0.56
Error :
Cannot read property 'favIcon' of undefined
Sample Code :
const fav = require('../../images/favorite.png');
const nonfav = require('../../images/not_favorite.png');
updateFavorite = (id) => {
this.props.refs.favIcon.source(fav);
}
render(){
return (
<View style={styles.container}>
<TouchableWithoutFeedback onPress={ this.updateFavorite.bind(this, 1) }>
<View style={ styles.imageView }>
<Image refs="favIcon" source={ nonfav } />
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={ this.updateFavorite.bind(this, 2) }>
<View style={ styles.imageView }>
<Image refs="favIcon" source={ nonfav } />
</View>
</TouchableWithoutFeedback>
</View>
)
}
Note : change only the child image of onPressed, not all images.
try it using nativeProps, like
import resolveAssetSource from 'resolveAssetSource';
this.refs['favIcon'].setNativeProps({
src: [resolveAssetSource(fav)]
});
refer this for more.
It might not work with react-native 0.50+ versions but according to this comment it should work with 0.57.1
Updating properties of elements in React is best done by calling setState method. Try the following
updateFavorite = (event) => {
event.target.setAttribute('src', fav)
}
render(){
return (
<View style={styles.container}>
<TouchableWithoutFeedback>
<View style={ styles.imageView }>
<img ref={ref => this.favIcon = ref} src={nonFav} onPress={ this.updateFavorite }/>
</View>
</TouchableWithoutFeedback>
<TouchableWithoutFeedback>
<View style={ styles.imageView }>
<img ref={ref => this.favIcon = ref} src={nonFav} onPress={ this.updateFavorite } />
</View>
</TouchableWithoutFeedback>
</View>
)
}

Categories

Resources