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

React Native中BottomSheet Modal点击触发内部错误求助

问题修复:React Native BottomSheet Modal 操作面板点击报错

错误信息

Warning: Internal React error: Attempted to capture a commit phase error inside a detached tree. This indicates a bug in React. Likely causes include deleting the same fiber more than once, committing an already-finished tree, or an inconsistent return pointer.

TypeError: undefined is not a function
in BottomSheet (created by BottomSheet)

错误分析

该错误是由多方面问题共同引发的:闭包导致的过时引用、组件属性名不匹配、空值调用函数/属性、条件逻辑漏洞,最终导致BottomSheet组件状态异常,触发React内部的detached tree错误。

具体修复步骤

1. 修复renderBackdrop的闭包依赖问题

useCallback的依赖数组未包含fRef和props.animatedPosition,导致闭包捕获的是过时值,调用dismiss时可能找不到正确组件实例:

const renderBackdrop = useCallback((props) => {
  const opacityStyle = useAnimatedStyle(
    () => ({
      opacity: (800 - props.animatedPosition.value) / 896,
    }),
    [props.animatedPosition] // 加入动画位置依赖
  );

  return (
    <Animated.View
      style={[
        StyleSheet.absoluteFillObject,
        { backgroundColor: "#000000", borderWidth: 1 },
        opacityStyle,
      ]}
    >
      <TouchableOpacity
        onPress={() => fRef.current?.dismiss()}
        style={StyleSheet.absoluteFillObject}
      />
    </Animated.View>
  );
}, [fRef]); // 加入ref到依赖数组

2. 统一选项的图标字段名

resend选项使用了小写icon字段,其他选项都是大写Icon,如果ActionListContainer期望大写属性,会导致渲染错误:

// 原resend选项
options.push({
  id: "resend",
  title: "Resend message",
  icon: Resend, // 改为大写Icon
  handler: callHandlerAndDismissSheet.bind(null, actionHandlers?.resendMessage),
});

// 修改后
options.push({
  id: "resend",
  title: "Resend message",
  Icon: Resend,
  handler: callHandlerAndDismissSheet.bind(null, actionHandlers?.resendMessage),
});

3. 处理chatClient空值情况

调用pinMessage/unpinMessage前先判断chatClient是否存在,避免调用undefined的方法:

const pin = async () => {
  if (!chatClient) return;
  await chatClient.pinMessage(message, null);
};
const unpin = async () => {
  if (!chatClient) return;
  await chatClient.unpinMessage(message);
};

4. 安全调用propMessageReactionPicker

添加可选链调用,避免未传递该函数时触发错误:

const openReactionPicker = () => {
  propMessageReactionPicker?.(message);
};

5. 优化pin/unpin的条件判断逻辑

简化判断并确保message.pinned_by存在再访问属性:

else {
  const isPinned = message.pinned ?? false;
  if (!isPinned) {
    options.push({
      Icon: Pin,
      handler: callHandlerAndDismissSheet.bind(null, pin),
      id: "pin/unpin",
      title: Title,
    });
  } else {
    if (message.pinned_by && chatClient.user.id === message.pinned_by.id) {
      options.push({
        Icon: Unpin,
        handler: callHandlerAndDismissSheet.bind(null, unpin),
        id: "pin/unpin",
        title: Title,
      });
    }
  }
}

6. 全局空值防护

在组件开头添加空值判断,避免后续访问属性时出错:

export const MessageActionSheetSlack = React.forwardRef((props, fRef) => {
  const { activeMessage: message, activeChannel: channel } = useContext(AuthContext);
  const { actionHandlers, openReactionPicker: propMessageReactionPicker } = props;
  const chatClient = ChatClientService.getClient();

  const navigation = useNavigation();
  const actionHandlersExist = !!actionHandlers;

  // 空值直接返回null,避免后续报错
  if (!actionHandlersExist || !message || !channel || !chatClient) {
    return null;
  }

  // ... 后续代码
});

总结

以上修复解决了闭包引用、属性不匹配、空值调用、逻辑漏洞等问题,组合起来就能消除点击操作时的报错。

内容的提问来源于stack exchange,提问作者Nishada Dilshan Weerathunga

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:43:18