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

React Native Bottom Sheet Modal状态变更时动态高度偶发失效

Gorhom Bottom Sheet Modal 高度未随内容变化正确更新问题

场景

我使用Gorhom的Bottom Sheet Modal实现了一个带秒表界面的模态框,其中包含一个用于标记计时的TextInput输入框。我为该输入框添加了onFocus和onBlur事件,通过useState(布尔值状态)来隐藏/显示界面中的两个元素,目的是在用户输入时简化界面,显示更多模态框后方的内容。

问题

useState的状态切换完全正常,元素的显示/隐藏速度符合预期,但模态框的高度并非每次都会重新计算渲染。有时即使2/3的界面元素已被隐藏,模态框仍保持原有高度,当前代码仅能60%正常生效。
长按输入框时成功率能提升至90%以上,但用户不会知晓此操作,也不应要求用户这么做。

效果对比

正确效果错误效果
正确效果错误效果

相关代码片段

const slimModeHandler = () => {
  setTimeout(() => {
    setSlimMode((prevState) => {
      return true;
    });
  }, 500);
};
<View style={styles.textInputWrapper}>
  <View style={styles.textInputCol}>
    <BottomSheetTextInput
      style={styles.textInputField}
      placeholder="Name this lap"
      placeholderTextColor={GlobalStyles.colors.font500}
      clearButtonMode="always"
      maxLength={20}
      onChangeText={inputHandlerLapNameState}
      value={modalMemory.modalMemoryLapNameState}
      /* keyboardBehavior="interactive" */
      /* onPressIn={() => {
        setSlimMode((prevState) => {
          return true;
        });
      }} */
      onFocus={slimModeHandler}
      onBlur={() => {
        setSlimMode((prevState) => {
          return false;
        });
      }}
    />
  </View>
</View>
const dynamicContainerHeight = useMemo(() => {
  console.log("pre rerendering of dynamicContainerHeight", slimMode);
  //add 500 ms delay to slimMode

  /*  setTimeout(() => { */
  console.log("slimMode during timeOut", slimMode);
  return {
    ...styles.modalContainer,
    paddingBottom: 16,
    /*       height: 120, */
  };
  /*     }, 500); */
}, [slimMode]);
<BottomSheetView
  style={dynamicContainerHeight}
  onLayout={handleContentLayout}
>
</BottomSheetView>
{!slimMode ? (
  <TimerModalCreateStopwatch
    stopwatch={stopwatch}
    handleLeftButtonPress={handleLeftButtonPress}
    handleLeftButtonLongPress={handleLeftButtonLongPress}
    handleLeftButtonLongPressOut={handleLeftButtonLongPressOut}
    handleRightButtonPress={handleRightButtonPress}
    modalMemory={modalMemory}
  />
) : null}

环境差异

Mac的iOS模拟器上一切100%正常,无法排查问题,推测是旧Mac模拟器性能低于真机;在iPhone上开启远程调试后也能100%正常,推测是调试模式下渲染速度变慢导致时机匹配。因此我怀疑需要在某处添加延迟。

已尝试方案

  • 替换onFocus为onPressIn,成功率提升至80%,但状态切换过早,导致键盘上推输入框的动画体验不佳;
  • 添加console.log确认dynamicContainerHeight在onFocus和onBlur时能正确重渲染,结果正常;
  • 将dynamicContainerHeight存入状态中;
  • 用useCallback替代useMemo,并尝试在onFocus中调用;
  • 按照包作者建议移除dynamicContainerHeight以触发额外重渲染,但无效果;
  • 尝试包作者提供的keyboardBehavior自定义Hook;
  • 为dynamicContainerHeight和useState添加延迟;
  • 在dynamicContainerHeight中添加slimMode判断,状态变更时返回静态高度;
  • 添加KeyboardAvoidingView;
  • 尝试包作者提供的collapse方法;

已花费3-4天时间仍未解决,不知下一步该尝试什么。


解决方案建议

1. 手动触发Bottom Sheet高度重计算

利用Gorhom Bottom Sheet提供的ref,在slimMode状态变更后,强制触发高度重新计算:

import { BottomSheetModal, useBottomSheetModal } from '@gorhom/bottom-sheet';

// 组件内获取模态框ref
const { bottomSheetModalRef } = useBottomSheetModal();

// 修改状态更新逻辑,触发重计算
const slimModeHandler = () => {
  setSlimMode(true);
  // 等待DOM更新后执行,确保内容已变化
  requestAnimationFrame(() => {
    bottomSheetModalRef.current?.recalculateSnapPoints();
  });
};

const handleBlur = () => {
  setSlimMode(false);
  requestAnimationFrame(() => {
    bottomSheetModalRef.current?.recalculateSnapPoints();
  });
};

// 绑定到输入框
<BottomSheetTextInput
  // ...其他属性
  onFocus={slimModeHandler}
  onBlur={handleBlur}
/>

2. 通过key属性强制BottomSheetView重渲染

当slimMode变化时,修改BottomSheetView的key属性,强制组件重新渲染,让Bottom Sheet重新计算内容高度:

<BottomSheetView
  style={dynamicContainerHeight}
  onLayout={handleContentLayout}
  key={`bottom-sheet-content-${slimMode}`}
>
  {/* 模态框内容 */}
</BottomSheetView>

3. 优化SnapPoints配置

确保Bottom Sheet的snapPoints设置为自动适应内容,避免固定高度限制:

const snapPoints = useMemo(() => ['auto'], []);

// 在BottomSheetModal中使用
<BottomSheetModal
  ref={bottomSheetModalRef}
  snapPoints={snapPoints}
  // ...其他配置
>
  {/* 内容 */}
</BottomSheetModal>

4. 移除不必要的延迟

你当前slimModeHandler中的500ms延迟可能和Bottom Sheet的内部渲染逻辑冲突,尝试移除延迟,改为依赖requestAnimationFrame确保时机正确:

const slimModeHandler = () => {
  setSlimMode(true);
  requestAnimationFrame(() => {
    bottomSheetModalRef.current?.recalculateSnapPoints();
  });
};

内容的提问来源于stack exchange,提问作者Boavista_Ludwig

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 14:01:02