I'm developing a Map Application which uses a JSON file to plot markers and render information on landmarks. Currently I have implement the React Native Carousel feature which also snaps to the landmark item when a marker is pressed. It also snaps the Carousel item to the currently selected marker. However I also wish to implement a bottom sheet, which can scroll up and render extra information: Landmark name and description.
Using the same method as rendering the carousel data: name and image, I'm getting an error when trying to render the current landmark in the bottomscreen.
Error Message:
TypeError: undefined is not an object (evaluating '_ref2.item')
In my code renderInner is the function which should render the bottomsheet with the descirption whilst also calling the renderHeader function - which should render the header of the bottomsheet to contain the title of the landmark - "name".
Here is my current code:
import React, { Component } from "react";
import { StyleSheet,View, Text, Image, Dimensions } from "react-native";
import MapView, {PROVIDER_GOOGLE, Marker, Callout } from "react-native-maps";
import Carousel from "react-native-snap-carousel";
import { LinearGradient } from "expo-linear-gradient";
import BottomSheet from 'reanimated-bottom-sheet';
import Animated from 'react-native-reanimated';
const { block, set, greaterThan, lessThan, Value, cond, sub } = Animated
const windowHeight = Dimensions.get("window").height;
export default class ParisMap extends Component {
// BottomScreen Constants
trans = new Value(0)
untraversedPos = new Value(0)
prevTrans = new Value(0)
headerPos = block([
cond(
lessThan(this.untraversedPos, sub(this.trans, 100)),
set(this.untraversedPos, sub(this.trans, 100))
),
cond(
greaterThan(this.untraversedPos, this.trans),
set(this.untraversedPos, this.trans)
),
set(this.prevTrans, this.trans),
this.untraversedPos,
])
static navigationOptions = {
title: "Map",
};
state = {
markers: [],
coordinates: [
{
name: "Louvre Museum",
latitude: 48.86074344,
longitude: 2.337659481,
Description: "Former historic palace housing huge art collection, from Roman sculptures to da Vinci's 'Mona Lisa.'",
image: require("../assets/louvre.jpeg"),
},
{
name: "Arc de Triomphe",
latitude: 48.87389506,
longitude: 2.295039178,
Description: "Iconic triumphal arch built to commemorate Napoleon's victories, with an observation deck.",
image: require("../assets/louvre.jpeg"),
},
{
name: "Eiffel Tower",
latitude: 48.85841765,
longitude: 2.294465185,
Description: "Gustave Eiffel's iconic, wrought-iron 1889 tower, with steps and elevators to observation decks.",
image: require("../assets/louvre.jpeg"),
},
{
name: "Cathédrale Notre-Dame",
latitude: 48.85294707,
longitude: 2.350142233,
Description: "Towering, 13th-century cathedral with flying buttresses & gargoyles, setting for Hugo's novel.",
image: require("../assets/louvre.jpeg"),
},
{
name: "Sacré-Cœur",
latitude: 48.88670304,
longitude: 2.343082828,
Description: "Iconic, domed white church, completed in 1914, with interior mosaics, stained-glass windows & crypt.",
image: require("../assets/louvre.jpeg"),
},
],
};
onCarouselItemChange = (index) => {
let location = this.state.coordinates[index];
this._map.animateToRegion({
latitude: location.latitude,
longitude: location.longitude,
latitudeDelta: 0.0045,
longitudeDelta: 0.0045,
});
this.state.markers[index].showCallout();
};
onMarkerPressed = (location, index) => {
this._map.animateToRegion({
latitude: location.latitude,
longitude: location.longitude,
latitudeDelta: 0.0045,
longitudeDelta: 0.0045,
});
this._carousel.snapToItem(index);
this._bottomsheet.snapToItem(index);
};
renderCarouselItem = ({ item }) => (
<View style={styles.cardContainer}>
<Text style={styles.cardTitle}>{item.name}</Text>
<Image style={styles.cardImage} source={item.image} />
</View>
);
renderInner = ({ item }) => (
<View style={styles.bottomSheetInnerContainer}>
<Animated.View
style={{
zIndex: 1,
transform: [
{
translateY: this.headerPos,
},
],
}}
>
{this.renderHeader({ item })}
</Animated.View>
{/* <Text style={styles.descriptionText}> Here is some sample text</Text> */}
<Text style={styles.descriptionText}> {item.Description}</Text>
</View>
)
renderHeader = ({ item }) => (
// Header View section - to display name of location
<View style={styles.headerContainer}>
{/* <Text style={styles.locationHeader}>Name of Place</Text> */}
<Text style={styles.locationHeader}>{item.name}</Text>
<Image source={require("../assets/upArrow.png")} style={styles.arrowLogo}></Image>
</View>
);
render() {
return (
<View style={styles.container}>
<MapView
provider={PROVIDER_GOOGLE}
ref={(map) => (this._map = map)}
showsUserLocation={true}
style={styles.map}
initialRegion={{
latitude: 48.84574344,
longitude: 2.325659581,
latitudeDelta: 0.155,
longitudeDelta: 0.155,
}}
>
{this.state.coordinates.map((marker, index) => (
<Marker
key={marker.name}
ref={(ref) => (this.state.markers[index] = ref)}
onPress={() => this.onMarkerPressed(marker, index)}
coordinate={{
latitude: marker.latitude,
longitude: marker.longitude,
}}
>
<Callout>
<Text>{marker.name}</Text>
</Callout>
</Marker>
))}
</MapView>
<View style={styles.bottomView}>
<LinearGradient
style={styles.gradient}
colors={["rgba(0, 0, 0,0)", "rgba(0, 0, 0,1)"]}
/>
</View>
<Carousel
ref={(c) => {
this._carousel = c;
}}
data={this.state.coordinates}
containerCustomStyle={styles.carousel}
renderItem={this.renderCarouselItem}
sliderWidth={Dimensions.get("window").width}
itemWidth={300}
removeClippedSubviews={false}
onSnapToItem={(index) => this.onCarouselItemChange(index)}
/>
<BottomSheet
ref={(c) => {
this._bottomsheet = c;
}}
data={this.state.coordinates}
renderItem={this.renderHeader}
contentPosition={this.trans}
snapPoints={[100, 400]}
renderContent={this.renderInner}
onSnapToItem={(index) => this.onCarouselItemChange(index)}
/>
</View>
);
}
}
const IMAGE_SIZE = 200
const styles = StyleSheet.create({
container: {
...StyleSheet.absoluteFillObject,
},
map: {
...StyleSheet.absoluteFillObject,
},
gradient: {
...StyleSheet.absoluteFillObject,
height: 5,
bottom: 0,
},
bottomView: {
width: "100%",
height: 25,
justifyContent: "center",
alignItems: "center",
position: "absolute",
bottom: 200,
},
carousel: {
position: "absolute",
bottom: 0,
marginBottom: 0,
backgroundColor: "#ececec",
height: 220,
},
cardContainer: {
backgroundColor: "rgba(0, 0, 0, 0.6)",
height: 200,
width: 300,
padding: 15,
borderRadius: 24,
marginTop: 10,
},
cardImage: {
height: 150,
width: 300,
bottom: 0,
position: "absolute",
borderBottomLeftRadius: 24,
borderBottomRightRadius: 24,
},
cardTitle: {
color: "white",
fontSize: 20,
alignSelf: "center",
},
cardDescription: {
color: "white",
fontSize: 18,
alignSelf: "flex-start",
},
headerContainer: {
width: '100%',
backgroundColor: '#ececec',
borderWidth: 0.5,
paddingVertical: 20,
justifyContent: 'center',
flexDirection: 'row',
justifyContent: 'space-between',
},
locationHeader: {
fontSize: 18,
position: "relative",
fontWeight: "bold",
marginLeft: 15,
},
arrowLogo: {
height: 20,
width: 20,
opacity: 0.5,
marginRight: 15,
},
bottomSheetContainer: {
backgroundColor: 'white'
},
bottomSheetInnerContainer: {
width: "100%",
color: "white",
backgroundColor: "white",
height: 800
},
descriptionText: {
fontSize: 20,
paddingVertical: 30,
marginLeft: 20
}
});
I believe my error is within the renderInner and/or renderHeader functions however after trying many different methods I can't get it working.
When I comment out the line in the renderHeader function:
<Text style={styles.locationHeader}>{item.name}</Text>
and also the line in the renderInner function:
<Text style={styles.descriptionText}> {item.Description}</Text>
Everything else works just fine, besides rendering the title and description as I would like to. Is there a reason why I'm getting this error?
Data is not present in the bottom sheet!
When you call renderItem you have to pass the single coordinate!
for example:
renderItem={() => this.renderHeader(this.state.coordinates[0])}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.