Здравствуйте, я новичок в React Native, и в настоящее время у меня проблема с моим модальным компонентом. Мой модальный компонент имеет два реквизита: gameData и isModalVisible. В Home.js модальное свойство isModalVisible имеет значение переменной состояния isVisible, которая изменяется на true при нажатии определенной TouchableOpacity. Затем внутри моего FeaturedGameModal.js isModalVisible устанавливается из реквизита. У меня проблема с закрытием модального окна. Открытие модального окна таким образом работает нормально, но как мне закрыть модальное окно, поскольку его видимость контролируется реквизитами, которые находятся в Home.js? Любая помощь будет принята с благодарностью. Я работаю над этим уже два дня, и это сводит меня с ума. Спасибо! Я включу два своих файла на случай, если вы захотите более внимательно изучить мой код.
Главная.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.info(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,
},
});
Вы должны создать функцию hideModal в Home.js, а затем передать ее компоненту Modalz.
В Home.js добавьте эту функцию:
hideModalz = () => {
this.setState({isVisible: true});
}
И передайте эту функцию реквизитам Modalz:
<Modalz
gameData = {this.state.featuredGameData.featuredGame}
isModalVisible = {this.state.isVisible}
hide = {hideModalz}
/>
В Modalz вызовите this.props.hide();
, если хотите скрыть модальное окно.
Спасибо! Моя функция, переданная модальному модулю, немного отличается, но это заставило меня двигаться в правильном направлении. Я ценю вашу помощь!