如何将@gorhom bottom sheet封装为独立可复用组件并解决ref未定义问题
解决方案
完全可以抽离为可复用的独立Modal/BottomSheet组件,你遇到的ref为undefined问题是React组件默认不透传ref属性导致的,可通过forwardRefAPI解决。
问题原因
React的函数组件默认不会将接收的ref属性传递给内部嵌套的组件,你抽离的自定义组件没有做ref转发时,绑定到自定义组件上的ref无法指向内部的第三方BottomSheet实例,因此会返回undefined。
具体实现步骤
1. 封装独立的BottomSheet组件
使用forwardRef包裹你的自定义组件,将接收的ref绑定到内部的BottomSheet实例上,同时通过props接收自定义配置、子内容:
import React, { forwardRef } from 'react'; import BottomSheet from '@gorhom/bottom-sheet'; import { View, StyleSheet } from 'react-native'; const CustomBottomSheet = forwardRef((props, ref) => { // 从props解构配置项,可根据需求扩展支持更多参数 const { snapPoints = ['25%', '50%'], index = 0, onChange, handleComponent, children } = props; return ( <BottomSheet ref={ref} // 核心:把透传的ref绑定到底层BottomSheet实例 snapPoints={snapPoints} index={index} onChange={onChange} handleComponent={handleComponent ?? (() => <View style={styles.defaultHandle} />)} > <View style={styles.contentContainer}> {children /* 承载外部传入的自定义内容 */} </View> </BottomSheet> ) }) const styles = StyleSheet.create({ defaultHandle: { height: 4, width: 40, backgroundColor: '#eee', borderRadius: 2, alignSelf: 'center', marginVertical: 12 }, contentContainer: { paddingHorizontal: 16, paddingBottom: 24 } }) export default CustomBottomSheet;
2. 父组件调用方式
和你之前直接调用第三方BottomSheet的方式完全一致,直接绑定ref、传入配置和自定义内容即可:
import React, { useRef, useCallback } from 'react'; import { View, Text, Button } from 'react-native'; import CustomBottomSheet from './components/CustomBottomSheet'; const HomePage = () => { const bottomSheetRef = useRef(null); const snapPoints = ['30%', '60%']; const handleSheetChanges = useCallback((index) => { console.log('bottom sheet state:', index); }, []); const openSheet = () => { // 可正常调用底层BottomSheet的实例方法 bottomSheetRef.current?.expand(); } return ( <View style={{flex:1}}> <Button title="打开底部弹窗" onPress={openSheet} /> <CustomBottomSheet ref={bottomSheetRef} snapPoints={snapPoints} onChange={handleSheetChanges} > {/* 传入当前页面需要的自定义内容 */} <Text>这是首页专属的BottomSheet内容</Text> <Button title="其他操作" onPress={()=>{}} /> </CustomBottomSheet> </View> ) } export default HomePage;
可选扩展
如果你需要给封装的CustomBottomSheet暴露自定义的实例方法,不想父组件直接调用底层BottomSheet的原生方法,可以配合useImperativeHandleAPI实现:
// 在CustomBottomSheet组件内部新增逻辑 import { useImperativeHandle, useRef } from 'react'; const CustomBottomSheet = forwardRef((props, ref) => { const innerRef = useRef(null); // 暴露自定义方法给外部ref useImperativeHandle(ref, () => ({ open: () => innerRef.current?.expand(), close: () => innerRef.current?.close(), // 还可以扩展其他自定义方法 snapToIndex: (index) => innerRef.current?.snapToIndex(index) })) return ( <BottomSheet ref={innerRef} // 其余参数保持不变 > {/* 内容逻辑保持不变 */} </BottomSheet> ) })
内容的提问来源于stack exchange,提问作者Alba
相关产品推荐
相关产品推荐

