React Native条件渲染下Modal关闭前短暂闪烁问题解决咨询
解决React Native Modal关闭时的闪烁问题
问题根源
你在每个条件渲染的下拉区域里都嵌套了一个AddressModal组件,这意味着当条件渲染触发(比如选中Division后显示District),页面中会同时存在多个AddressModal实例。这些实例共享同一个isModalVisible状态,当关闭Modal时,多个实例的渲染状态同步变化,导致视觉上的闪烁。
核心修复方案
将AddressModal从各个下拉组件中移除,只在整个SignupPresentAddress组件的根层级渲染一次。这样始终只有一个Modal实例,避免多实例状态同步冲突。
修改后的SignupPresentAddress代码
import { View, Text, TextInput, Pressable, Image, Modal } from 'react-native' import React, { useEffect, useState } from 'react' import { useGeolocationStore, useUserStore } from '../app/stores/store.js' import GradientButton from '../components/GradientButton' import AddressModal from '../components/AddressModal' const SignupPresentAddress = ({ setCurrentComponent }) => { const { user, setSelectedAddressType, setSelectedAddressCategory } = useUserStore() const [isModalVisible, setIsModalVisible] = useState(false) const [isDivisionSelected, setIsDivisionSelected] = useState(false) const [isDistrictSelected, setIsDistrictSelected] = useState(false) const [isUpazilaSelected, setIsUpazilaSelected] = useState(false) useEffect(() => { setIsDivisionSelected(!!(user.presentAddress?.division)) setIsDistrictSelected(!!(user.presentAddress?.district)) setIsUpazilaSelected(!!(user.presentAddress?.upazila)) }, [user.presentAddress]) const handlePrevButtonPress = () => { setCurrentComponent('m-verification') } const handleNextButtonPress = () => { setCurrentComponent('permanent-address') } const handlePressDropdown = (category) => { setSelectedAddressCategory(category) setIsModalVisible(true) } useEffect(() => { setSelectedAddressType('present') }, []) return ( <> <Text className='mt-4 text-2xl text-center text-white'>Present Address</Text> <View className='w-full max-w-[360px] mt-4 gap-y-4'> <View> <Text className='text-white text-lg'>Division</Text> <Pressable onPress={() => handlePressDropdown('divisions')} > <View className='relative'> <TextInput className='bg-white rounded-full text-lg mt-2 px-5 py-3 p-4' value={user?.presentAddress?.division?.name} editable={false} /> <Image className='absolute w-10 h-10 right-3 top-3' source={require('../assets/icons/expand-arrow-down.png')} /> </View> </Pressable> </View> {isDivisionSelected && ( <View> <Text className='text-white text-lg'>District</Text> <Pressable onPress={() => handlePressDropdown('districts')} > <View className='relative'> <TextInput className='bg-white rounded-full text-lg mt-2 px-5 py-3 p-4' value={user?.presentAddress?.district?.name} editable={false} /> <Image className='absolute w-10 h-10 right-3 top-3' source={require('../assets/icons/expand-arrow-down.png')} /> </View> </Pressable> </View> )} {isDistrictSelected && ( <View> <Text className='text-white text-lg'>Sub-district</Text> <Pressable onPress={() => handlePressDropdown('upazilas')} > <View className='relative'> <TextInput className='bg-white rounded-full text-lg mt-2 px-5 py-3 p-4' value={user?.presentAddress?.upazila?.name} editable={false} /> <Image className='absolute w-10 h-10 right-3 top-3' source={require('../assets/icons/expand-arrow-down.png')} /> </View> </Pressable> </View> )} {isUpazilaSelected && ( <View> <Text className='text-white text-lg'>Union</Text> <Pressable onPress={() => handlePressDropdown('unions')} > <View className='relative'> <TextInput className='bg-white rounded-full text-lg mt-2 px-5 py-3 p-4' value={user?.presentAddress?.union?.name} editable={false} /> <Image className='absolute w-10 h-10 right-3 top-3' source={require('../assets/icons/expand-arrow-down.png')} /> </View> </Pressable> </View> )} <View> <Text className='text-white text-lg'>Address Line 1 (e.g. House / Road / Village)</Text> <TextInput className='bg-white rounded-full text-lg mt-2 px-5 py-3 p-4' placeholder='Address Line 1 (e.g. House / Road / Village)' numberOfLines={1} /> </View> <View> <Text className='text-white text-lg'>Address Line 2 (e.g. Area / Post Office)</Text> <TextInput className='bg-white rounded-full text-lg mt-2 px-5 py-3 p-4' placeholder='Address Line 2 (e.g. Area / Post Office)' numberOfLines={1} /> </View> <View className='flex-row w-full justify-between mt-4'> <GradientButton handlePress={handlePrevButtonPress} > <Text className='text-xl text-dark1 text-center'>Previous</Text> </GradientButton> <GradientButton handlePress={handleNextButtonPress} > <Text className='text-xl text-dark1 text-center'>Next</Text> </GradientButton> </View> </View> {/* 仅渲染一次AddressModal */} <AddressModal isModalVisible={isModalVisible} setIsModalVisible={setIsModalVisible} /> </> ) } export default SignupPresentAddress
额外优化建议
- 简化状态判断:用
!!快速将可选值转为布尔类型,精简useEffect内的逻辑 - 明确Modal触发逻辑:修改
handlePressDropdown,先设置分类再打开Modal,避免Modal显示时数据未准备完全
内容的提问来源于stack exchange,提问作者Romjan Ali
相关产品推荐
相关产品推荐

