React Native Expo中BottomSheet渲染数据项时出现TypeError问题求助
嘿,我帮你定位到问题的核心了!你遇到的TypeError: undefined is not an object (evaluating '_ref2.item'),本质是对reanimated-bottom-sheet的API理解有误:
你错误地以为BottomSheet的renderContent(也就是你的renderInner函数)会像React Native Carousel的renderItem一样,自动传入包含当前项的{item}参数,但实际上它并不会。renderContent只是用来渲染底部抽屉的静态结构,不会自动遍历你的coordinates数据——所以你试图访问item.name和item.Description时,item根本就是undefined,自然就抛出了类型错误。
下面是一步步的解决方案:
1. 在状态中添加当前选中索引
首先给组件的state新增一个currentIndex字段,用来跟踪当前选中的地标位置:
state = { markers: [], currentIndex: 0, // 新增这一行,默认选中第一个地标 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"), }, ], };
2. 更新索引切换函数,同步currentIndex
修改onCarouselItemChange和onMarkerPressed函数,在切换地标时同步更新currentIndex,这样BottomSheet就能拿到最新的选中项:
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(); // 新增:更新当前选中索引 this.setState({ currentIndex: index }); }; onMarkerPressed = (location, index) => { this._map.animateToRegion({ latitude: location.latitude, longitude: location.longitude, latitudeDelta: 0.0045, longitudeDelta: 0.0045, }); this._carousel.snapToItem(index); // 注意!这里之前写错了:BottomSheet的snapToItem是切换到指定的snap点索引,不是地标索引 this._bottomsheet.snapToItem(1); // 1对应你设置的400高度,展开抽屉 // 新增:更新当前选中索引 this.setState({ currentIndex: index }); };
3. 重写renderInner和renderHeader,从state取数据
去掉这两个函数的{item}参数,直接从state中获取当前选中的地标数据:
renderInner = () => { // 从state拿到当前选中的地标 const currentItem = this.state.coordinates[this.state.currentIndex]; return ( <View style={styles.bottomSheetInnerContainer}> <Animated.View style={{ zIndex: 1, transform: [{ translateY: this.headerPos }] }} > {this.renderHeader(currentItem)} </Animated.View> <Text style={styles.descriptionText}> {currentItem.Description}</Text> </View> ) } renderHeader = (item) => ( <View style={styles.headerContainer}> <Text style={styles.locationHeader}>{item.name}</Text> <Image source={require("../assets/upArrow.png")} style={styles.arrowLogo}></Image> </View> );
4. 清理BottomSheet的无效props
BottomSheet不需要data和renderItem这些Carousel专属的配置,把它们删掉:
<BottomSheet ref={(c) => { this._bottomsheet = c; }} contentPosition={this.trans} snapPoints={[100, 400]} renderContent={this.renderInner} // 移除不需要的data、renderItem、onSnapToItem(如果不需要抽屉高度切换时联动地图的话) />
如果希望抽屉切换高度时有额外逻辑,可以保留onSnapToItem,但要注意它的参数是snap点的索引(0对应100高度,1对应400高度),不是地标索引。
这样修改后,当你点击标记或者切换Carousel项时,currentIndex会同步更新,BottomSheet就能正确渲染当前选中地标的名称和描述,再也不会出现undefined的错误啦!
内容的提问来源于stack exchange,提问作者RickPeck

