React Native + Expo中useEffect自动聚焦在Android Box端报错
问题核心原因
你遇到的报错本质有两层原因:
- 从React Native原生设计逻辑上,
TouchableWithoutFeedback组件本身不支持Android TV/Box的焦点交互能力——它是纯JS层的触摸包裹组件,不会渲染对应的原生可聚焦视图,自然不会把focus()这类系统方法透传到绑定的ref上。 - 本地Expo开发环境下,React的开发模式补丁会给组件ref附加模拟的focus/blur方法,所以调试时调用不会报错;到Android Box的Expo Go实机环境下,运行的是不带开发补丁的生产逻辑,ref实例上根本不存在focus方法,直接调用就会触发
focus is not a function的TypeError。
具体解决方案
1. 替换支持原生焦点能力的可点击组件
- 把原来的
TouchableWithoutFeedback替换为Pressable、TouchableOpacity这类在原生层实现了焦点逻辑的组件,这类组件会自动把原生视图的focus()、blur()方法透传到绑定的ref上,实机环境下也能正常调用 - 不要在useEffect里硬调用focus方法,加上可选链做防御判断,避免组件ref还未挂载完成时触发空值报错
- 针对Android Box的焦点扫描规则,给可点击组件显式加上
focusable={true}属性,否则系统可能不会把该组件纳入方向键的焦点遍历范围
2. 调整自动聚焦的触发时机
Android Box上的原生视图挂载延迟比普通手机、本地模拟器高,空依赖的useEffect执行时,组件可能还没完成原生层的绑定,哪怕组件支持focus方法也会调用失败。可以加100ms左右的延时触发聚焦,确认视图完全挂载后再执行focus调用。
修正后的可运行代码示例
import { StyleSheet, Image, View, Pressable } from 'react-native'; import * as React from 'react'; const HomeScreen = ({navigation}) => { const goToNextScreen = React.useRef(null) React.useEffect(() => { const focusTimer = setTimeout(() => { // 防御性判断,避免空引用报错 goToNextScreen.current?.focus() }, 100) // 组件卸载时清理定时器,避免内存泄漏 return () => clearTimeout(focusTimer) }, []); return ( <View style={styles.container}> <Pressable ref={goToNextScreen} focusable={true} onPress={() => navigation.navigate('NextPage')}> <Image source={require('../assets/img/logo.png')} /> </Pressable> </View> ); } export default HomeScreen;
内容的提问来源于stack exchange,提问作者Ricardo Couto
相关产品推荐
相关产品推荐

