React Native Paper TextInput在自定义Modal中输入时出现字符闪烁/消失问题
我看到你遇到了TextInput在自定义Modal里输入时字符反复闪烁的问题,结合你的代码和React Native常见的坑,我来帮你分析可能的原因和对应的解决方案:
可能的原因及解决方案
1. 自定义Modal的memo优化导致不必要重渲染
你的CustomModal用了React.memo做性能优化,但默认的浅比较会把每次渲染时生成的新children(也就是包含TextInput的View)判定为不同的props。每次输入字符时,FriendAddModal会因为friendCode状态变化重渲染,生成新的children传给CustomModal,触发CustomModal和内部TextInput的重复渲染,最终导致闪烁。
解决方案:
给TextInput所在的区域做局部渲染隔离,用React.memo包裹成独立组件,减少不必要的重渲染:
// 在FriendAddModal组件内部定义 const FriendCodeInput = memo(({ label, value, onChangeText, colors, t }) => ( <TextInput label={label} value={value} onChangeText={onChangeText} mode="flat" style={{ backgroundColor: 'rgba(255, 255, 255, 0.1)', marginHorizontal: 10 }} placeholder={t('friendAddModal.friendCodePlaceholder')} theme={{ colors: { primary: colors.primary, placeholder: colors.text, text: colors.text, }, fonts: { regular: { fontFamily: 'Orbitron-ExtraBold' } }, }} autoCapitalize="none" autoCorrect={false} keyboardType="default" left={<TextInput.Icon icon="magnify" color={colors.primary} />} /> ));
然后在FriendAddModal的return里替换原有TextInput:
<View style={{ paddingVertical: 35 }}> <FriendCodeInput label={t('friendAddModal.friendCodeLabel')} value={friendCode} onChangeText={setFriendCode} colors={colors} t={t} /> </View>
2. 自定义字体未预加载导致闪烁
你给TextInput设置了Orbitron-ExtraBold自定义字体,如果字体没有在App启动时预加载,每次输入字符时系统都需要临时加载字体资源,就会出现字符闪烁的情况。
解决方案:
确保自定义字体已正确预加载:
- 如果是Expo项目,用
expo-font和AppLoading预加载:
// App.js中 import { useFonts } from 'expo-font'; import AppLoading from 'expo-app-loading'; export default function App() { const [fontsLoaded] = useFonts({ 'Orbitron-ExtraBold': require('./assets/fonts/Orbitron-ExtraBold.ttf'), }); if (!fontsLoaded) { return <AppLoading />; } return <YourRootComponent />; }
- 如果是裸React Native项目,把字体文件放到
android/app/src/main/assets/fonts和ios/[项目名]/Resources/Fonts目录,配置react-native.config.js后重启项目即可。
3. React Native Paper Modal与自定义动画的冲突
你的CustomModal同时使用了react-native-paper的Modal组件和自定义Animated动画,动画逻辑可能干扰了TextInput的正常渲染,导致状态波动。
解决方案:
简化Modal动画,改用react-native-paper Modal自带的动画:
// 修改CustomModal组件,去掉自定义Animated逻辑 const CustomModal = memo(({ visible, onDismiss, onConfirm, children, title, text, confirmText = 'Confirm', showConfirmButton = false, }) => { const { colors } = useTheme(); const { t } = useTranslation(); return ( <Portal> <Modal visible={visible} onDismiss={onDismiss} animationType="slide" // 使用自带的滑入动画 contentContainerStyle={[ styles.modalContainer, { backgroundColor: colors.background }, ]} > <View style={styles.content}> {title && <Text style={[styles.title, { color: colors.text }]}>{title}</Text>} {text && <Text style={[styles.text, { color: colors.text }]}>{text}</Text>} {children} <View style={styles.buttonContainer}> <Button mode="outlined" onPress={onDismiss} style={styles.closeButton} labelStyle={styles.closeButtonLabel}> {t('customModal.cancel')} </Button> {showConfirmButton && ( <Button mode="contained" onPress={onConfirm} style={styles.confirmButton} labelStyle={styles.confirmButtonLabel}> {confirmText} </Button> )} </View> </View> </Modal> </Portal> ); });
4. 受控组件状态更新的微小延迟(排查用)
虽然你的受控组件写法是正确的,但可以尝试用函数式更新确保状态的实时性,排查是否是状态更新延迟导致的闪烁:
<TextInput // 其他props不变 onChangeText={(text) => setFriendCode(prev => text)} />
排查步骤建议
- 先临时去掉自定义字体
Orbitron-ExtraBold,如果闪烁消失,说明是字体预加载的问题; - 若字体没问题,再尝试给TextInput做局部memo优化,减少重渲染;
- 最后再排查Modal动画的冲突问题。
内容来源于stack exchange

