admin管理员组文章数量:1246502
I am using a Modal in my React Native app to display address selection options. The modal works fine, but when I use conditional rendering to show dropdown fields based on selected values, the modal flickers for a brief moment before closing. If I remove the conditional rendering, the issue disappears.
I tried adding a small delay using setTimeout(() => setIsModalVisible(false), 100), but it didn't work. The issue persists, and I’m unsure how to fix it. How can I prevent this flickering while keeping the conditional rendering?
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(() => {
if(user.presentAddress && user.presentAddress.division) {
setIsDivisionSelected(true)
}
if(user.presentAddress && user.presentAddress.district) {
setIsDistrictSelected(true)
}
if(user.presentAddress && user.presentAddress.upazila) {
setIsUpazilaSelected(true)
}
}, [user.presentAddress])
const handlePrevButtonPress = () => {
setCurrentComponent('m-verification')
}
const handleNextButtonPress = () => {
setCurrentComponent('permanent-address')
}
const handlePressDropdown = () => {
setIsModalVisible((prevState) => !prevState)
}
// set selected address type to present when the component is rendered
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()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</View>
{isDivisionSelected && (
<View>
<Text className='text-white text-lg'>District</Text>
<Pressable
onPress={() => {
handlePressDropdown()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</View>
)}
{isDistrictSelected && (
<View>
<Text className='text-white text-lg'>Sub-district</Text>
<Pressable
onPress={() => {
handlePressDropdown()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</View>
)}
{isUpazilaSelected && (
<View>
<Text className='text-white text-lg'>Union</Text>
<Pressable
onPress={() => {
handlePressDropdown()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</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>
</>
)
}
export default SignupPresentAddress
import { View, Text, Modal, TouchableOpacity, FlatList, StyleSheet } from 'react-native'
import React, { useEffect, useState } from 'react'
import { useGeolocationStore, useUserStore } from '../app/stores/store.js'
const AddressModal = ({
isModalVisible,
setIsModalVisible,
}) => {
const { divisions, districts, upazilas, unions } = useGeolocationStore()
const { user, updateUser, selectedAddressType, selectedAddressCategory } = useUserStore()
const [filteredDistricts, setFilteredDistricts] = useState([])
const [filteredUpazilas, setFilteredUpazilas] = useState([])
const [filteredUnions, setFilteredUnions] = useState([])
const handleSelect = (item) => {
if (selectedAddressType === 'present') {
if (selectedAddressCategory === 'divisions') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
division: item,
district: null,
upazila: null,
union: null,
}
})
const filtered_districts = districts.filter((district) =>
item.id === district.division_id
)
setFilteredDistricts(filtered_districts)
} else if (selectedAddressCategory === 'districts') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
district: item,
upazila: null,
union: null,
}
})
const filtered_upazila = upazilas.filter((upazila) =>
item.id === upazila.district_id
)
setFilteredUpazilas(filtered_upazila)
} else if (selectedAddressCategory === 'upazilas') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
upazila: item,
union: null,
}
})
const filtered_union = unions.filter((union) =>
item.id === union.upazilla_id
)
setFilteredUnions(filtered_union)
} else if (selectedAddressCategory === 'unions') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
union: item,
}
})
}
} else if (selectedAddressType === 'permanent') {
if (selectedAddressCategory === 'divisions') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
division: item,
district: null,
upazila: null,
union: null,
}
})
const filtered_districts = districts.filter((district) =>
item.id === district.division_id
)
setFilteredDistricts(filtered_districts)
} else if (selectedAddressCategory === 'districts') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
district: item,
upazila: null,
union: null,
}
})
const filtered_upazila = upazilas.filter((upazila) =>
item.id === upazila.district_id
)
setFilteredUpazilas(filtered_upazila)
} else if (selectedAddressCategory === 'upazilas') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
upazila: item,
union: null,
}
})
const filtered_union = unions.filter((union) =>
item.id === union.upazilla_id
)
setFilteredUnions(filtered_union)
} else if (selectedAddressCategory === 'unions') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
union: item,
}
})
}
}
setIsModalVisible(false)
}
return (
<View>
<Modal
visible={isModalVisible}
transparent
animationType="fade"
onRequestClose={() => setIsModalVisible(false)}
>
<TouchableOpacity
style={styles.modalBackground}
onPress={() => setIsModalVisible(false)}
>
<View style={styles.dropdownContainer}>
<FlatList
data={
selectedAddressCategory === 'divisions' ? divisions
: selectedAddressCategory === 'districts' ? filteredDistricts
: selectedAddressCategory === 'upazilas' ? filteredUpazilas
: selectedAddressCategory === 'unions' ? filteredUnions
: null
}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<>
<TouchableOpacity
style={styles.option}
onPress={() => handleSelect(item)}
>
<Text style={styles.optionText}>{item.name}</Text>
</TouchableOpacity>
<View style={styles.lastOption} />
</>
)}
/>
</View>
</TouchableOpacity>
</Modal>
</View>
)
}
export default AddressModal
const styles = StyleSheet.create({
container: {
padding: 16,
},
dropdownButton: {
padding: 12,
backgroundColor: '#f0f0f0',
borderRadius: 8,
borderWidth: 1,
borderColor: '#ccc',
},
buttonText: {
fontSize: 16,
},
modalBackground: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.2)',
},
dropdownContainer: {
width: '80%',
height: '80%',
backgroundColor: 'white',
borderRadius: 8,
padding: 16,
elevation: 4,
},
option: {
padding: 12,
borderTopWidth: 1,
borderTopColor: '#ddd',
},
lastOption: {
borderBottomWidth: 1,
borderBottomColor: '#ddd',
},
optionText: {
fontSize: 16,
textAlign: 'center'
},
});
I tried using conditional rendering to show and hide the modal when selecting an item. However, when I select an item, the modal briefly reappears before closing. I expected the modal to close immediately without flickering. I also attempted adding a short delay (setTimeout
) before updating the state, but the issue persists.
I am using a Modal in my React Native app to display address selection options. The modal works fine, but when I use conditional rendering to show dropdown fields based on selected values, the modal flickers for a brief moment before closing. If I remove the conditional rendering, the issue disappears.
I tried adding a small delay using setTimeout(() => setIsModalVisible(false), 100), but it didn't work. The issue persists, and I’m unsure how to fix it. How can I prevent this flickering while keeping the conditional rendering?
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(() => {
if(user.presentAddress && user.presentAddress.division) {
setIsDivisionSelected(true)
}
if(user.presentAddress && user.presentAddress.district) {
setIsDistrictSelected(true)
}
if(user.presentAddress && user.presentAddress.upazila) {
setIsUpazilaSelected(true)
}
}, [user.presentAddress])
const handlePrevButtonPress = () => {
setCurrentComponent('m-verification')
}
const handleNextButtonPress = () => {
setCurrentComponent('permanent-address')
}
const handlePressDropdown = () => {
setIsModalVisible((prevState) => !prevState)
}
// set selected address type to present when the component is rendered
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()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</View>
{isDivisionSelected && (
<View>
<Text className='text-white text-lg'>District</Text>
<Pressable
onPress={() => {
handlePressDropdown()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</View>
)}
{isDistrictSelected && (
<View>
<Text className='text-white text-lg'>Sub-district</Text>
<Pressable
onPress={() => {
handlePressDropdown()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</View>
)}
{isUpazilaSelected && (
<View>
<Text className='text-white text-lg'>Union</Text>
<Pressable
onPress={() => {
handlePressDropdown()
setSelectedAddressCategory('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>
<AddressModal
isModalVisible={isModalVisible}
setIsModalVisible={setIsModalVisible}
/>
</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>
</>
)
}
export default SignupPresentAddress
import { View, Text, Modal, TouchableOpacity, FlatList, StyleSheet } from 'react-native'
import React, { useEffect, useState } from 'react'
import { useGeolocationStore, useUserStore } from '../app/stores/store.js'
const AddressModal = ({
isModalVisible,
setIsModalVisible,
}) => {
const { divisions, districts, upazilas, unions } = useGeolocationStore()
const { user, updateUser, selectedAddressType, selectedAddressCategory } = useUserStore()
const [filteredDistricts, setFilteredDistricts] = useState([])
const [filteredUpazilas, setFilteredUpazilas] = useState([])
const [filteredUnions, setFilteredUnions] = useState([])
const handleSelect = (item) => {
if (selectedAddressType === 'present') {
if (selectedAddressCategory === 'divisions') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
division: item,
district: null,
upazila: null,
union: null,
}
})
const filtered_districts = districts.filter((district) =>
item.id === district.division_id
)
setFilteredDistricts(filtered_districts)
} else if (selectedAddressCategory === 'districts') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
district: item,
upazila: null,
union: null,
}
})
const filtered_upazila = upazilas.filter((upazila) =>
item.id === upazila.district_id
)
setFilteredUpazilas(filtered_upazila)
} else if (selectedAddressCategory === 'upazilas') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
upazila: item,
union: null,
}
})
const filtered_union = unions.filter((union) =>
item.id === union.upazilla_id
)
setFilteredUnions(filtered_union)
} else if (selectedAddressCategory === 'unions') {
updateUser({
...user,
presentAddress: {
...user.presentAddress,
union: item,
}
})
}
} else if (selectedAddressType === 'permanent') {
if (selectedAddressCategory === 'divisions') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
division: item,
district: null,
upazila: null,
union: null,
}
})
const filtered_districts = districts.filter((district) =>
item.id === district.division_id
)
setFilteredDistricts(filtered_districts)
} else if (selectedAddressCategory === 'districts') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
district: item,
upazila: null,
union: null,
}
})
const filtered_upazila = upazilas.filter((upazila) =>
item.id === upazila.district_id
)
setFilteredUpazilas(filtered_upazila)
} else if (selectedAddressCategory === 'upazilas') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
upazila: item,
union: null,
}
})
const filtered_union = unions.filter((union) =>
item.id === union.upazilla_id
)
setFilteredUnions(filtered_union)
} else if (selectedAddressCategory === 'unions') {
updateUser({
...user,
permanentAddress: {
...user.permanentAddress,
union: item,
}
})
}
}
setIsModalVisible(false)
}
return (
<View>
<Modal
visible={isModalVisible}
transparent
animationType="fade"
onRequestClose={() => setIsModalVisible(false)}
>
<TouchableOpacity
style={styles.modalBackground}
onPress={() => setIsModalVisible(false)}
>
<View style={styles.dropdownContainer}>
<FlatList
data={
selectedAddressCategory === 'divisions' ? divisions
: selectedAddressCategory === 'districts' ? filteredDistricts
: selectedAddressCategory === 'upazilas' ? filteredUpazilas
: selectedAddressCategory === 'unions' ? filteredUnions
: null
}
keyExtractor={(item) => item.id}
renderItem={({ item }) => (
<>
<TouchableOpacity
style={styles.option}
onPress={() => handleSelect(item)}
>
<Text style={styles.optionText}>{item.name}</Text>
</TouchableOpacity>
<View style={styles.lastOption} />
</>
)}
/>
</View>
</TouchableOpacity>
</Modal>
</View>
)
}
export default AddressModal
const styles = StyleSheet.create({
container: {
padding: 16,
},
dropdownButton: {
padding: 12,
backgroundColor: '#f0f0f0',
borderRadius: 8,
borderWidth: 1,
borderColor: '#ccc',
},
buttonText: {
fontSize: 16,
},
modalBackground: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.2)',
},
dropdownContainer: {
width: '80%',
height: '80%',
backgroundColor: 'white',
borderRadius: 8,
padding: 16,
elevation: 4,
},
option: {
padding: 12,
borderTopWidth: 1,
borderTopColor: '#ddd',
},
lastOption: {
borderBottomWidth: 1,
borderBottomColor: '#ddd',
},
optionText: {
fontSize: 16,
textAlign: 'center'
},
});
I tried using conditional rendering to show and hide the modal when selecting an item. However, when I select an item, the modal briefly reappears before closing. I expected the modal to close immediately without flickering. I also attempted adding a short delay (setTimeout
) before updating the state, but the issue persists.
1 Answer
Reset to default 0Hey! Here's a quick explanation:
The flickering issue happens because React sees functions and objects (like renderItem
or inline functions) as new on every render, so it re-creates them and triggers re-renders. To fix this, you can move those functions outside the render cycle.
Also, I see you're trying to dismiss the Modal when the backdrop is pressed, consider using a Pressable
instead of TouchableOpacity
e.g:
const hideModal = () => setIsModalVisible(false);
const renderItem = ({ item }) => (
<>
<TouchableOpacity
style={styles.option}
onPress={() => handleSelect(item)}>
<Text style={styles.optionText}>{item.name}</Text>
</TouchableOpacity>
<View style={styles.lastOption} />
</>
);
return (
<View>
<Modal
visible={isModalVisible}
transparent
animationType="fade"
onRequestClose={hideModal}>
<Pressable style={styles.modalBackground} onPress={hideModal}>
<View style={styles.dropdownContainer}>
<FlatList
data={data}
keyExtractor={(item) => item.id}
renderItem={renderItem} //Function now reused instead of recreated
/>
</View>
</Pressable>
</Modal>
</View>
);
Other Tips:
- If you're working with different datasets, consider using a
switch
statement to improve readability oruseMemo
to avoid unnecessary calculations e.g:
const dataToDisplay = useMemo(() => {
switch (selectedCategory) {
case 'option1':
return option1Data;
case 'option2':
return option2Data;
default:
return [];
}
}, [selectedCategory, option1Data, option2Data]);
. . .
<FlatList
data={dataToDisplay}
. . .
/>
- Cleaning up the component and breaking it into smaller parts can also help readability.
- For more tips on optimizing React performance, check out this article on React Optimization Tips.
Goodluck!
本文标签: React Native Modal Flickers Briefly Before Closing When Using Conditional RenderingStack Overflow
版权声明:本文标题:React Native Modal Flickers Briefly Before Closing When Using Conditional Rendering - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1740265138a2251021.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论