切换组件时搜索输入框自动失焦?求保持键盘常亮方案
解决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的变化,当组件切换完成后通知输入框重新聚焦。
- 实现
usePrevious钩子记录上一次参数值:
import { useRef, useEffect } from 'react'; function usePrevious<T>(value: T) { const ref = useRef<T>(); useEffect(() => { ref.current = value; }, [value]); return ref.current; }
- 修改
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> ) }
- 修改
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> } </> ) }
- 修改
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
相关产品推荐
相关产品推荐

