由不同组件打开的 React Native 关闭 Modal
Posted
技术标签:
【中文标题】由不同组件打开的 React Native 关闭 Modal【英文标题】:React Native close Modal that is opened by different component 【发布时间】:2021-03-23 05:08:22 【问题描述】:您好,我是 React Native 的新手,目前我的模态组件有问题。我的模态组件有两个道具,gameData 和 isModalVisible。在 Home.js 中,模态属性 isModalVisible 具有状态变量 isVisible 的值,当按下某个 TouchableOpacity 时,该值变为 true。然后在我的 FeaturedGameModal.js 中 isModalVisible 是从道具设置的。我遇到的问题是关闭模式。以这种方式打开模态很好,但是我应该如何关闭模态,因为它的可见性是由 Home.js 中的道具控制的?任何帮助将不胜感激。我已经为此工作了两天,这让我发疯。谢谢!如果您想更仔细地检查我的代码,我将包含我的两个文件。
Home.js:
import React from 'react';
import
View,
Text,
Image,
SafeAreaView,
TouchableOpacity,
ActivityIndicator,
Linking,
ScrollView,
TouchableHighlight,
from 'react-native';
import homeStyles from '../styles/homeStyles';
import styles from '../styles/styles';
import createIconSetFromIcoMoon from 'react-native-vector-icons';
import icoMoonConfig from '../../assets/fonts/selection.json';
import fetchData from '../functions/fetch';
import Modalz from '../modals/FeaturedGameModal';
const Icon = createIconSetFromIcoMoon(icoMoonConfig);
class Home extends React.Component
myData = ;
constructor(props)
super(props);
this.state =
error: false,
isFetching: true,
featuredGameModal: false,
isVisible: false,
;
handleFeaturedGame = async () =>
this.setState(, async () =>
try
const featureGameData = await fetchData(
'http://dev.liberty.edu/templates/flames/json/json_appHomeFeed.cfm',
);
this.setState(
error: false,
featuredGameData: featureGameData,
isFetching: false,
);
catch (e)
this.setState(
error: true,
);
console.log(e.message);
);
;
handleFeaturedModal()
this.setState(featuredGameModal: false);
componentDidMount()
this.handleFeaturedGame();
render()
const featuredGameData = this.state;
return this.state.isFetching ? (
<View style=styles.center>
<ActivityIndicator size="large" color="#AE0023" />
</View>
) : (
<ScrollView>
<SafeAreaView>
<View style=homeStyles.featuredGameContainer>
<View style=homeStyles.centerHor>
<Image
style=homeStyles.logo
source=require('../../assets/images/FlamesLogo.png')
/>
</View>
<View style=homeStyles.gameTimeContainer>
<Text style=homeStyles.gameTime>
featuredGameData.featuredGame.eventdate
</Text>
<Text style=homeStyles.gameTime>
featuredGameData.featuredGame.eventtime
</Text>
</View>
<TouchableOpacity
activeOpacity=0.6
onPress=() =>
this.setState(isVisible: true);
>
<View style=homeStyles.contentContainer>
<View style=homeStyles.contentLeft>
<Text style=homeStyles.teamText>
featuredGameData.featuredGame.teamname
</Text>
<Text style=homeStyles.opponentText>
vs featuredGameData.featuredGame.opponent
</Text>
<Text style=homeStyles.locationText>
<Icon size=12 name='location' />
featuredGameData.featuredGame.location
</Text>
</View>
<View style=homeStyles.contentRight>
<Image
style=homeStyles.opponentLogo
source=
uri: featuredGameData.featuredGame.OpponentLogoFilename,
/>
</View>
</View>
</TouchableOpacity>
<View style=homeStyles.allContent>
<Modalz
gameData=this.state.featuredGameData.featuredGame
isModalVisible=this.state.isVisible
/>
<View style=homeStyles.contentContainerBottom>
<View style=homeStyles.contentLeft>
<TouchableOpacity
style=homeStyles.buyTicketBtn
onPress=() =>
Linking.openURL(featuredGameData.featuredGame.buyTickets)
>
<Text style=homeStyles.buyTicketBtnText>Buy Tickets</Text>
</TouchableOpacity>
</View>
<View style=homeStyles.liveContainer>
<Text style=homeStyles.live>Experience Live:</Text>
<View style=homeStyles.liveIconsContainer>
<Icon
style=color: '#FFF', marginRight: 4
size=15
name='radio'
/>
<Icon style=color: '#FFF' size=12 name='LFSN' />
</View>
</View>
</View>
</View>
</View>
<View style=homeStyles.newsContainer>
featuredGameData.News.map((item, key) => (
<View
key=key
style=[homeStyles.centerHor, homeStyles.newsCard]>
<Image
style=homeStyles.newsImage
source=
uri: item.Thumbnail,
/>
<Text style=homeStyles.headline>item.Headline</Text>
<View style=homeStyles.teamNameView>
<Text style=homeStyles.teamNameText>item.teamname</Text>
<Text>item.GameDate</Text>
</View>
</View>
))
</View>
</SafeAreaView>
</ScrollView>
);
export default Home;
FeaturedGameModal.js:
import React from 'react';
import
Alert,
Modal,
StyleSheet,
Text,
TouchableHighlight,
View,
Image,
Dimensions,
TouchableOpacity,
SafeAreaView,
from 'react-native';
import createIconSetFromIcoMoon from 'react-native-vector-icons';
import icoMoonConfig from '../../assets/fonts/selection';
import homeStyles from '../styles/homeStyles';
const Icon = createIconSetFromIcoMoon(icoMoonConfig);
const windowWidth = Dimensions.get('window').width;
export default class Modalz extends React.Component
constructor(props)
super(props);
this.state =
teamName: props.gameData.teamname,
opponentName: props.gameData.opponent,
eventDate: props.gameData.eventdate,
liveAudioURL: props.gameData.LiveAudioURL,
liveStatsURL: props.gameData.LiveStatsURL,
videoURL: props.gameData.VideoURL,
opponentLogoURL: props.gameData.OpponentLogoFilename,
;
render()
const
opponentName,
teamName,
eventDate,
opponentLogoURL,
liveStatsURL,
liveAudioURL,
videoURL,
location,
= this.state;
const isModalVisible = this.props;
return (
<View>
<View style=styles.centeredView>
<Modal
animationType="slide"
transparent=true
visible=isModalVisible
onRequestClose=() =>
Alert.alert('Modal has been closed.');
>
<SafeAreaView style=flex: 1, backgroundColor: 'transparent'>
<View style=styles.centeredView>
<View style=styles.modalView>
<Icon
style=styles.closeButton
size=25
name='x'
onPress=() =>
/>
<Text style=styles.upcomingGameTitle>
teamName vs opponentName
</Text>
<Text style=styles.upcomingGameSubtitle>eventDate</Text>
<View style=styles.facingLogosBlock>
<View style=styles.leftTeamBlock />
<View style=styles.rightTeamBlock />
<View style=styles.vsTextWrapper>
<Text style=styles.vsText>VS</Text>
</View>
<View style=styles.logoWrapper>
<Image
style=styles.facingLogoImg
source=
uri:
'https://www.liberty.edu/templates/flames/images/flamesMonogram.png',
/>
<Image
style=styles.facingLogoImg
source=uri: opponentLogoURL
/>
</View>
</View>
<View>
<TouchableOpacity style=styles.buyTicketBtn>
<Text style=styles.buyTicketBtnText>Buy Tickets</Text>
</TouchableOpacity>
</View>
<View style=styles.buttonRow>
<TouchableOpacity
style=...styles.iconButton, ...styles.iconButtonLeft>
<Icon
style=styles.iconButtonIcon
size=25
name='flag'
onPress=() =>
this.toggleModal(!this.state.modalVisible);
/>
<Text style=styles.iconButtonText>Game Day</Text>
</TouchableOpacity>
<TouchableOpacity
style=...styles.iconButton, ...styles.iconButtonRight>
<Icon
style=styles.iconButtonIcon
size=25
name='stats'
onPress=() =>
this.toggleModal(!this.state.modalVisible);
/>
<Text style=styles.iconButtonText>Live Stats</Text>
</TouchableOpacity>
</View>
<View style=styles.liveLinkBlock>
<View style=styles.liveLinkLeft>
<Icon
style=styles.iconButtonIcon
size=18
name='LFSN'
/>
<Text>The Journey 88.3 FM</Text>
</View>
<TouchableOpacity style=styles.liveButton>
<Text style=styles.liveButtonText>Listen Live</Text>
</TouchableOpacity>
</View>
<View style=styles.liveLinkBlock>
<View style=styles.liveLinkLeft>
<Icon
style=styles.iconButtonIcon
size=18
name='espn3'
/>
<Text>LFSN TV Production</Text>
</View>
<TouchableOpacity style=styles.liveButton>
<Text style=styles.liveButtonText>Watch Live</Text>
</TouchableOpacity>
</View>
</View>
</View>
</SafeAreaView>
</Modal>
</View>
</View>
);
const styles = StyleSheet.create(
centeredView:
flex: 1,
justifyContent: 'center',
alignItems: 'center',
,
modalView:
flex: 1,
alignSelf: 'stretch',
backgroundColor: 'white',
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
paddingTop: 14,
alignItems: 'center',
shadowColor: '#000',
shadowOffset:
width: 0,
height: 2,
,
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
,
openButton:
backgroundColor: '#F194FF',
borderRadius: 20,
padding: 10,
elevation: 2,
,
closeButton:
position: 'absolute',
right: 16,
top: 16,
color: '#000',
,
closeText:
color: '#000',
fontWeight: 'bold',
textAlign: 'center',
fontSize: 20,
,
upcomingGameTitle:
color: '#19191A',
fontSize: 18,
fontWeight: 'bold',
,
upcomingGameSubtitle:
color: '#747676',
fontSize: 13,
fontWeight: 'bold',
marginBottom: 16,
,
modalText:
marginBottom: 15,
textAlign: 'center',
,
facingLogosBlock:
flexDirection: 'row',
position: 'relative',
alignItems: 'center',
,
facingLogoImg:
width: 100,
height: 100,
resizeMode: 'contain',
flex: 1,
,
leftTeamBlock:
width: 0,
height: 0,
backgroundColor: 'transparent',
borderStyle: 'solid',
borderRightWidth: 35,
borderTopWidth: 185,
borderRightColor: 'transparent',
borderTopColor: '#AE0023',
borderLeftColor: '#AE0023',
borderLeftWidth: windowWidth / 2,
left: 15,
zIndex: -1,
position: 'relative',
,
rightTeamBlock:
width: 0,
height: 0,
backgroundColor: 'transparent',
borderStyle: 'solid',
borderLeftWidth: 35,
borderBottomWidth: 185,
borderBottomColor: '#461964',
borderRightColor: '#461964',
borderLeftColor: 'transparent',
borderRightWidth: windowWidth / 2,
right: 15,
zIndex: -1,
position: 'relative',
,
vsTextWrapper:
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
,
vsText:
color: '#000000',
backgroundColor: '#FFFFFF',
padding: 5,
fontWeight: 'bold',
,
logoWrapper:
position: 'absolute',
width: windowWidth,
height: 185,
top: 0,
left: 35,
flexDirection: 'row',
alignItems: 'center',
,
buyTicketBtn:
marginTop: 24,
backgroundColor: '#AE0023',
borderRadius: 4,
paddingVertical: 20,
paddingHorizontal: 12,
width: windowWidth - 24,
,
buyTicketBtnText:
fontSize: 21,
color: '#fff',
fontWeight: 'bold',
alignSelf: 'center',
textTransform: 'uppercase',
,
buttonRow:
paddingVertical: 24,
paddingHorizontal: 12,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
,
iconButton:
backgroundColor: '#F0F3F5',
borderRadius: 4,
paddingVertical: 14,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
flex: 1,
,
iconButtonText:
color: '#19191A',
fontWeight: 'bold',
fontSize: 16,
marginLeft: 10,
,
iconButtonIcon:
color: '#000',
,
iconButtonLeft:
marginRight: 6,
,
iconButtonRight:
marginLeft: 6,
,
liveLinkBlock:
padding: 12,
borderStyle: 'solid',
borderTopColor: '#F0F3F5',
borderTopWidth: 1,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
,
liveButton:
backgroundColor: '#F0F3F5',
borderRadius: 4,
paddingVertical: 14,
flex: 1,
justifyContent: 'center',
alignItems: 'center',
,
liveButtonText:
color: '#19191A',
fontWeight: 'bold',
fontSize: 16,
,
liveLinkLeft:
flex: 2,
,
);
【问题讨论】:
【参考方案1】:您应该在 Home.js 中创建 hideModal 函数,然后将其传递给 Modalz 组件。
在 Home.js 中,添加这个函数:
hideModalz = () =>
this.setState(isVisible: true);
并将这个函数传递给 Modalz 道具:
<Modalz
gameData=this.state.featuredGameData.featuredGame
isModalVisible=this.state.isVisible
hide=hideModalz
/>
在 Modalz 中,如果您想隐藏 modal,请致电 this.props.hide();
。
【讨论】:
谢谢!我传递给模态的函数有点不同,但这让我朝着正确的方向前进。感谢您的帮助!以上是关于由不同组件打开的 React Native 关闭 Modal的主要内容,如果未能解决你的问题,请参考以下文章
React-Native:将焦点设置到由数组构建的自定义组件