简体   繁体   中英

Type Error When Rendering Item to Bottomsheet in React Native Expo

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM