Expo 34.0.0中Text组件setNativeProps失效及聚焦异常问题咨询
嘿,我来帮你搞定在Expo 34.0.0里遇到的这两个样式修改问题~
问题1:Text组件用ref调用setNativeProps返回undefined
这其实不是React Native的bug,而是<Text>组件的设计特性——它的ref并没有直接暴露原生视图的setNativeProps方法(尤其是在Expo 34这类较早版本中)。Text组件更多是作为文本渲染容器,原生层的动态样式控制支持度远不如TextInput这类输入组件,所以你调用refTitle.current.setNativeProps才会拿到undefined。
解决方案:改用state驱动Text的样式
放弃用ref修改Text的样式,转而用状态变量来控制。比如定义一个isInputFocused的state,在TextInput的onFocus和onBlur里更新这个状态,然后Text的样式根据状态切换即可。这种方式既符合React的数据流理念,又不会遇到原生组件的兼容性问题。
问题2:state方法导致需要两次点击才能获得焦点
这个问题的根源是:当你在onFocus里同步修改state时,组件会立刻触发重渲染,这个重渲染过程会打断TextInput的焦点获取流程——第一次点击触发onFocus后,state更新导致组件重绘,TextInput的原生视图被重新渲染,原本的焦点状态直接丢失,所以需要再点一次才能唤起键盘。
解决方案:用useCallback稳定事件处理函数,避免重渲染干扰焦点
把你的焦点处理函数用useCallback包裹,保证组件重渲染时不会生成新的函数实例,同时让state更新在React的正常数据流里执行,不会干扰原生焦点的绑定。
给你写个完整的示例代码:
import React, { useState, useRef, useCallback } from 'react'; import { Text, TextInput, View, StyleSheet } from 'react-native'; const FOCUS_COLOR = '#1677ff'; const BLUR_COLOR = '#ccc'; export default function YourComponent() { const [isInputFocused, setIsInputFocused] = useState(false); const refUser = useRef(null); const refPassword = useRef(null); // 用useCallback稳定函数引用,避免不必要的重渲染 const handleFocus = useCallback(() => { setIsInputFocused(true); }, []); const handleBlur = useCallback(() => { setIsInputFocused(false); }, []); return ( <View style={styles.container}> <Text style={[ styles.title, isInputFocused ? { color: FOCUS_COLOR } : {} ]} > as </Text> <TextInput ref={refUser} style={[ styles.input, isInputFocused ? { borderColor: FOCUS_COLOR } : { borderColor: BLUR_COLOR } ]} onSubmitEditing={() => refPassword.current?.focus()} onFocus={handleFocus} onBlur={handleBlur} /> {/* 假设这里是密码输入框 */} <TextInput ref={refPassword} style={styles.input} secureTextEntry /> </View> ); } const styles = StyleSheet.create({ container: { padding: 16, }, title: { fontSize: 18, marginBottom: 12, color: '#333', }, input: { borderWidth: 1, padding: 10, borderRadius: 4, marginBottom: 16, }, });
如果还是有问题,也可以试试在handleFocus里延迟更新state,让焦点先完成绑定:
const handleFocus = useCallback(() => { // 延迟到下一个事件循环更新state,避免打断焦点流程 setTimeout(() => { setIsInputFocused(true); }, 0); }, []);
内容的提问来源于stack exchange,提问作者Dell Watson

