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

切换组件时搜索输入框自动失焦?求保持键盘常亮方案

解决React Native条件渲染组件时输入框键盘自动收起的问题

问题原因

当searchParam从空变为非空时,SearchRoot会卸载原有的历史/推荐组件并挂载SearchMain组件。这个组件卸载/挂载的过程会触发页面布局重绘,系统会判定输入框失去交互必要性,自动收起键盘。

解决方案

方案1:手动控制输入框焦点,切换后重新聚焦

给输入框添加引用,在内容变化后强制重新聚焦,确保键盘保持打开状态。

修改SearchHeader组件:

import { TextInput, useRef, requestAnimationFrame } from 'react-native';

const SearchHeader = () => {
  const navigation = useNavigation<NativeStackNavigationProp<RootStackParams>>();
  const dispatch = useDispatch();
  // 创建输入框引用
  const inputRef = useRef<TextInput>(null);
  const [searchText, setSearchText] = useState<string>('');
  
  const handleChangeText = (e: string) => {
    dispatch(setSearch({searchParam: e}));
    setSearchText(e);
    // 确保组件切换完成后再执行聚焦
    requestAnimationFrame(() => {
      inputRef.current?.focus();
    });
  };

  // 其余原有逻辑保持不变...

  return (
    <View style={s.container}>
      <View style={s.header}>
        <View style={s.backContainer}>
          <GoBackIcon onPress={handleGoBack} color='#555' />
        </View>
        <View style={s.inputContainer}>
          <SearchInput
            ref={inputRef} // 绑定引用到输入框
            value={searchText}
            onChangeText={handleChangeText}
            onPressSearched={handlePressSeach}
            onPressClearTextField={handleClearText}
            autoFocus={true}
            style={s.sInput}
          />
        </View>
      </View>
    </View>
  )
}

方案2:避免组件完全卸载,用样式控制显示隐藏

不通过条件渲染卸载/挂载组件,而是用opacity、height样式控制组件可见性,保持组件在DOM树中存在,避免焦点丢失。

修改SearchRoot组件:

const SearchRoot = ({ }: ISearchRoot) => {
  const searchParam = useSelector((state: RootState) => state.Search.searchParam);
  return (
    <>
      {/* 搜索列表 */}
      <SearchMain 
        style={{ 
          opacity: searchParam.length > 0 ? 1 : 0,
          height: searchParam.length > 0 ? 'auto' : 0,
          overflow: 'hidden'
        }} 
      />
      {/* 历史/推荐文本 */}
      <Text 
        style={{ 
          opacity: searchParam.length === 0 ? 1 : 0,
          height: searchParam.length === 0 ? 'auto' : 0,
          overflow: 'hidden'
        }}
      >Vorschläge</Text>
    </>
  )
}

方案3:监听组件切换事件,触发重新聚焦

通过自定义hook监听searchParam的变化,当组件切换完成后通知输入框重新聚焦。

  1. 实现usePrevious钩子记录上一次参数值:
import { useRef, useEffect } from 'react';

function usePrevious<T>(value: T) {
  const ref = useRef<T>();
  useEffect(() => {
    ref.current = value;
  }, [value]);
  return ref.current;
}
  1. 修改Search组件传递聚焦回调:
const Search = () => {
  const [triggerFocus, setTriggerFocus] = useState(false);

  return (
    <View style={s.container}>
      <StatusBar backgroundColor='#fff' />
      <SearchHeader triggerFocus={triggerFocus} onFocusCompleted={() => setTriggerFocus(false)} />
      <SearchRoot onSwitchComplete={() => setTriggerFocus(true)} />
    </View>
  )
}
  1. 修改SearchRoot组件监听切换事件:
const SearchRoot = ({ onSwitchComplete }: ISearchRoot) => {
  const searchParam = useSelector((state: RootState) => state.Search.searchParam);
  const prevSearchParam = usePrevious(searchParam);

  useEffect(() => {
    // 从空变为非空时触发聚焦回调
    if (prevSearchParam?.length === 0 && searchParam.length > 0) {
      onSwitchComplete();
    }
  }, [searchParam, prevSearchParam, onSwitchComplete]);

  return (
    <>
      { searchParam.length > 0 ?
        <SearchMain />
        :
        <Text>Vorschläge</Text>
      }
    </>
  )
}
  1. 修改SearchHeader组件响应聚焦触发:
const SearchHeader = ({ triggerFocus, onFocusCompleted }: { triggerFocus: boolean, onFocusCompleted: () => void }) => {
  const inputRef = useRef<TextInput>(null);
  
  useEffect(() => {
    if (triggerFocus) {
      inputRef.current?.focus();
      onFocusCompleted();
    }
  }, [triggerFocus, onFocusCompleted]);

  // 其余原有逻辑保持不变...

  return (
    // ...
    <SearchInput ref={inputRef} />
    // ...
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:54:40