You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 14:27:04