Hello I am fairly new to React Native and am currently having an issue with my modal component. My modal component has two props, gameData and isModalVisible. In Home.js modal prop isModalVisible has the value of a state variable isVisible that gets changed to true when a certain TouchableOpacity is pressed. Then inside my FeaturedGameModal.js isModalVisible is set from props. The issue I am having is closing the modal. Opening the modal this way works fine, but how should I close the modal since its visibility is being controlled by props that are in Home.js? Any help would be greatly appreciated. I have been working on this for two days now and it is driving me crazy. Thanks! I will include my two files in case you want to more closely inspect my code.
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,
},
});
You should create hideModal function in Home.js then pass it to Modalz component.
In Home.js, add this function:
hideModalz = () => {
this.setState({isVisible: true});
}
And pass this function to Modalz props:
<Modalz
gameData={this.state.featuredGameData.featuredGame}
isModalVisible={this.state.isVisible}
hide={hideModalz}
/>
In Modalz, call this.props.hide();
if you want to hide modal.