我正在运行一个代码,该代码显示各种菜肴的菜单,用户可以在其中按一个菜肴,然后将其带到“菜肴细节”屏幕,以了解有关菜肴的信息。问题在于,当我们点击应用程序时正使用导航,但应用程序抛出了一些错误消息,提示“ TypeError:无法读取未定义的属性'navigate'”。您可以在下面的代码中看到我声明的代码。
MainComponent.js
import React, { Component } from 'react' ;
import Menu from './MenuComponent' ;
import { View, Image, StyleSheet, ScrollView, Text,Platform } from 'react-native'
//import { Platform } from '@unimodules/core';
import Home from './HomeComponent';
import Dishdetail from './DishdetailComponent' ;
import Contact from './ContactComponent' ;
import About from './AboutComponent';
import { Icon } from 'react-native-elements';
import { createStackNavigator, createDrawerNavigator,SafeAreaView,DrawerItems } from 'react-navigation';
//1. ActionCreators import
import { fetchDishes, fetchComments, fetchPromos, fetchLeaders} from '../redux/ActionCreators';
//1.import to connect to redux
import { connect } from 'react-redux';
import {baseUrl } from '../shared/baseUrl';
//2.leaders state from store
const mapStateToProps = state => {
return {
}
}
//2. get the actions creators
const mapDispatchToProps = dispatch => ({
fetchDishes: () => {dispatch(fetchDishes())},
fetchComments:() => {dispatch(fetchComments())},
fetchPromos: () => {dispatch(fetchPromos())},
fetchLeaders: () => {dispatch(fetchLeaders())}
})
//() => <Menu/>
const MenuNavigator = createStackNavigator({
Menu: { screen: () => <Menu/>,
navigationOptions: ({ navigation }) => ({
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={ () => navigation.toggleDrawer()}
/>
})
},
Dishdetail: { screen: () => <Dishdetail/> }
},
{
initialRouteName: 'Menu',
navigationOptions: {
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
}
}
})
//Create stacknavigator for Home Component
const HomeNavigator = createStackNavigator({
Home: { screen: () => <Home/> }
},
{
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
},
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={() => navigation.toggleDrawer()}
/>
})
});
//Create stacknavigator for Contact Component
const ContactNavigator = createStackNavigator({
Contact: { screen: () => <Contact/>}
},
{
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
},
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={() => navigation.toggleDrawer()}
/>
})
});
//Create stacknavigator for About Component
const AboutNavigator = createStackNavigator({
About: { screen: () => <About />}
},
{
navigationOptions: ({ navigation }) => ({
headerStyle: {
backgroundColor: '#512DA8'
},
headerTintColor: '#fff',
headerTitleStyle: {
color: '#fff'
},
headerLeft: <Icon name='menu' size={24}
color='white'
onPress={() => navigation.toggleDrawer()}
/>
})
});
const CustomDrawerContentComponent = (props) => (
<ScrollView>
<SafeAreaView style= {StyleSheet.container}
forceInset={{ top: 'always', horizontal: 'never'}} >
<View style={styles.drawerHeader} >
<View style={{flex:1}} >
<Image source={require('./images/logo.png')}
style={styles.drawerImage} />
</View>
<View style={{flex: 2}} >
<Text style={styles.drawerHeaderText} >Ristorante Con Fusion</Text>
</View>
</View>
<DrawerItems {...props } />
</SafeAreaView>
</ScrollView>
)
//Create drawerNavigator for all Components
// Modified
const MainNavigator = createDrawerNavigator({
Home:
{
screen: HomeNavigator,
navigationOptions: {
title: 'Home',
drawerLabel: 'Home',
drawerIcon: ({ tintColor }) => (
<Icon
name='home'
type='font-awesome'
size={24}
color={tintColor}
/>
)
}
},
About:
{
screen: AboutNavigator,
navigationOptions: {
title: 'About Us',
drawerLabel: 'About Us',
drawerIcon: ({ tintColor }) => (
<Icon
name='info-cirlce'
type='font-awesome'
size={24}
color={tintColor}
/>
)
}
},
Menu:
{
screen: MenuNavigator,
navigationOptions: {
title: 'Menu',
drawerLabel: 'Menu',
drawerIcon: ({ tintColor }) => (
<Icon
name='list'
type='font-awesome'
size={24}
color={tintColor}
/>
)
}
},
Contact:
{
screen: ContactNavigator,
navigationOptions: {
title: 'Contact Us',
drawerLabel: 'Contact Us',
drawerIcon: ({ tintColor }) => (
<Icon
name='address-card'
type='font-awesome'
size={22}
color={tintColor}
/>
)
}
}
},{
drawerBackgroundColor: '#D1C4E9',
contentComponent: CustomDrawerContentComponent
})
class Main extends Component {
//3. Actioncreators to be loaded by componentDidMount()
componentDidMount() {
this.props.fetchDishes();
this.props.fetchComments();
this.props.fetchPromos();
this.props.fetchLeaders();
}
//<Menu />:Display all dishes and when user clicks one of them
//<Dishdetail>: filter the selectedDish and display its detail underneath
render() {
return (
<View style={{flex: 1, paddingTop: Platform.OS === 'ios' ? 0: Expo.Constants.statusBarHeight }}>
<MainNavigator />
</View>
)
}
}
const styles = StyleSheet.create ({
container: {
flex: 1
},
drawerHeader:{
backgroundColor: '#512DA8',
height: 140,
alignItems: 'center',
justifyContent: 'center',
flex: 1,
flexDirection: 'row'
},
drawerHeaderText: {
color: 'white',
fontSize: 24,
fontWeight: 'bold'
},
drawerImage: {
margin: 10,
width: 80,
height: 60
}
})
export default connect(mapStateToProps, mapDispatchToProps)(Main);
MenuComponent.js
import React, { Component } from 'react' ;
import { FlatList } from 'react-native' ;
import { Tile } from 'react-native-elements' ;
//import { DISHES} from '../shared/dishes';
//1.import to connect to redux
import { connect } from 'react-redux';
import { baseUrl } from '../shared/baseUrl';
//2.leaders state from store
const mapStateToProps = state => {
return {
dishes: state.dishes
}
}
//functional component
class Menu extends Component {
constructor(props) {
super(props);
}
//display the Menu navigation at the top
static navigationOptions = {
title : 'Menu'
}
//onPress uses the navigate to pass the dishId to Dishsetail
//to display the dish detail of the selected dish
render() {
//const {navigate} = this.props.navigation ;
const renderMenuItem = ({item, index}) => {
return (
<Tile
key={index}
title={item.name}
caption={item.description}
featured
onPress={() => navigate('Dishdetail', { dishId: item.id })}
imageSrc={{ uri: baseUrl + item.image }}
/>
);
}
//extract the navigation comp passed to be used to pass
//dishId to Dishdetail
//const { navigate } = this.props.navigation ;
return (
<FlatList
data= {this.props.dishes.dishes}
renderItem={renderMenuItem}
keyExtractor={Item => Item.id.toString() }
/>
)
}
}
export default connect(mapStateToProps)(Menu);
DishdetailComponent.js
import React, { Component } from 'react' ;
import { View, Text, ScrollView, FlatList } from 'react-native' ;
import { Card, Icon } from 'react-native-elements' ;
//import { DISHES} from '../shared/dishes';
//import { COMMENTS } from '../shared/comments';
//1.import to connect to redux
import { connect } from 'react-redux';
import {baseUrl } from '../shared/baseUrl';
//2.leaders state from store
const mapStateToProps = state => {
return {
dishes: state.dishes,
comments: state.comments
}
}
//functional component: Display the selectedDish name, image and
//description using <Card> element
function RenderDish(props){
const dish = props.dish;
if (dish != null) {
return (
<Card
featuredTitle={dish.name}
image={{ uri: baseUrl + dish.image }}
>
<Text style={{margin: 10}}>
{dish.description}
</Text>
<Icon
raised
reverse
name={props.favorite ? 'heart' : 'heart-o'}
type='font-awesome'
color='#f50'
onPress={() => props.favorites ? console.log('Already favorite'): props.onPress() }
/>
</Card>
)
}
else {
return (<View></View>)
}
}
// display comments associted with dish
function RenderComments(props) {
// pull the content out from comments array
const comments = props.comments;
const renderCommentsItem = ({ item , index}) => {
return (
<View key={index} style={{ margin: 10}} >
<Text style={{fonSize: 14 }}>{item.comment}</Text>
<Text style={{fontSize: 12}}>{item.rating} Stars</Text>
<Text style={{ fontSize: 12}}>{'--' + item.author + ',' + item.date}</Text>
</View>
)
}
return (
<Card title="Comments">
<FlatList
data={comments}
renderItem={renderCommentsItem}
keyExtractor={item => item.id.toString()}
/>
</Card>
)
}
class Dishdetail extends Component {
constructor(props) {
super(props)
this.state = {
favorites: []
}
}
markFavourite(dishId) {
this.setState({favorites: this.state.favorites.concat(dishId)})
}
//setup the navigation for the current class [Dishdetail]
static navigationOptions = {
title : 'Dish Details'
}
render(){
// pass or extract the dish id through the navigation
const dishId = this.props.navigation.getParam('dishId', '');
return (
<ScrollView>
<RenderDish dish={this.props.dishes.dishes[+dishId]}
favorites={this.state.favorites.some(el => el === dishId)}
onPress={() => this.markFavourite(dishId)}/>
<RenderComments comments={this.props.comments.comments.filter((comment) => comment.dishId === dishId)} />
</ScrollView>
)
}
}
export default connect(mapStateToProps)(Dishdetail);