Reputation: 5
I'm trying to change the view from my search.js file. but I can't and I encounter this error in my app that crashes. And every time I do a console.log(this.props) in my search.js file I get this result :
------------------------------------opooi-
Object {}
.
This is my Search.js file
//Components/Search.js
import React from 'react'
import { StyleSheet, View, TextInput, Button, Text, FlatList, ActivityIndicator } from 'react-native'
import FilmItem from './FilmItems'
import { getFilmsFromApiWithSearchedText } from '../API/TMDBApi'
class Search extends React.Component {
_displayDetailForFilm = (idFilm) => {
//console.log("Display film with id " + idFilm + this )
console.log('----------------------opooi-')
console.log(this.props)
// Cette commande ci-dessous est non fonctionnel donc si vous avez la solution...
this.props.navigation.navigate("Details")
}
constructor(props) {
super(props)
this.page = 0
this.totalPages = 0
this.searchedText = "" // Initialisation de notre donnée searchedText en dehors du state
this.state = {
films: [],
isLoading : false // Affiche temoin de chargement desactiver de base
}
}
_loadFilms() {
this.setState({ isLoading: true})
if (this.searchedText.length > 0) { // Seulement si le texte recherché n'est pas vide
getFilmsFromApiWithSearchedText(this.searchedText, this.page+1).then(data => {
this.page = data.page
this.totalPages = data.total_pages
this.setState({
films: [...this.state.films , ...data.results ],
isLoading : false
})
})
}
}
_displayLoading() {
if (this.state.isLoading) {
return (
<View style={styles.loading_container}>
<ActivityIndicator size='large' />
{/* Le component ActivityIndicator possède une propriété size pour définir la taille du visuel de chargement : small ou large. Par défaut size vaut small, on met donc large pour que le chargement soit bien visible */}
</View>
)
}
}
_searchFilms() {
this.page = 0
this.totalPages = 0
this.setState({
films: []
}, ()=> {
// J'utilise la paramètre length sur mon tableau de films pour vérifier qu'il y a bien 0 film
console.log("Page : " + this.page + " / TotalPages : " + this.totalPages + " / Nombre de films : " + this.state.films.length)
this._loadFilms()
})
}
_searchTextInputChanged(text) {
this.searchedText = text // Modification du texte recherché à chaque saisie de texte, sans passer par le setState comme avant
}
render() {
const { film, displayDetailForFilm } = this.props
console.log('----------------------------')
console.log(this.props);
// test si lóbject this.props est null..
return (
<View
style={styles.main_container}
onPress={() => displayDetailForFilm(film.id)}
>
<TextInput
style={styles.textinput}
placeholder='Titre du film'
onChangeText={(text) => this._searchTextInputChanged(text)}
onSubmitEditing={() => this._searchFilms()}
/>
<Button title='Rechercher' onPress={() => this._searchFilms()}/>
<FlatList
data={this.state.films}
keyExtractor={(item) => item.id.toString()}
onEndReachedThreshold={0.5}
onEndReached={() => {
if (this.page < this.totalPages) {
this._loadFilms()
}
}}
This is my Navigation.js file
// Navigation/Navigation.js
import * as React from 'react';
import Search from '../Components/Search';
import FilmDetail from '../Components/FilmDetail';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
const Stack = createStackNavigator();
const HomeScreen =({ navigation }) => {
return (
<Search/>
);
}
const DetailsScreen = ({ navigation }) => {
return (
<FilmDetail/>
);
}
function Navigation() {
return (
<NavigationContainer>
<Stack.Navigator initialRouteName="Home">
<Stack.Screen name="Home" component={HomeScreen} options={{ title: 'Home' }} />
<Stack.Screen name="Details" component={DetailsScreen} options={{ title: 'Details' }} />
</Stack.Navigator>
</NavigationContainer>
);
}
export default Navigation;
Here is my Filmitem.js file where I use TouchableOpacity
// Components/FilmItem.js
import React from 'react'
import { StyleSheet, View, Text, Image, TouchableOpacity } from 'react-native'
import { getImageFromApi } from '../API/TMDBApi'
class FilmItem extends React.Component {
render() {
const film = this.props.film
const displayDetailForFilm = this.props.displayDetailForFilm
return (
<TouchableOpacity
style={styles.main_container}
onPress={() => displayDetailForFilm(film.id)}>
<Image
style={styles.image}
source={{uri: getImageFromApi(film.poster_path)}}
/>
<View style={styles.content_container}>
<View style={styles.header_container}>
<Text style={styles.title_text}>{film.title}</Text>
<Text style={styles.vote_text}>{film.vote_average}</Text>
</View>
<View style={styles.description_container}>
<Text style={styles.description_text} numberOfLines={6}>{film.overview}</Text>
{/* La propriété numberOfLines permet de couper un texte si celui-ci est trop long, il suffit de définir un nombre maximum de ligne */}
</View>
<View style={styles.date_container}>
<Text style={styles.date_text}>{film.release_date}</Text>
</View>
</View>
</TouchableOpacity>
)
}
}
const styles = StyleSheet.create({
main_container: {
height: 190,
flexDirection: 'row'
},
image: {
width: 120,
height: 180,
margin: 5,
backgroundColor: 'gray'
},
content_container: {
flex: 1,
margin: 5
},
header_container: {
flex: 3,
flexDirection: 'row'
},
title_text: {
fontWeight: 'bold',
fontSize: 20,
flex: 1,
flexWrap: 'wrap',
paddingRight: 5,
color: '#FFFFFF'
},
vote_text: {
fontWeight: 'bold',
fontSize: 26,
color: '#FFFFFF'
},
description_container: {
flex: 7
},
description_text: {
fontStyle: 'italic',
color: '#FFFFFF'
},
date_container: {
flex: 1
},
date_text: {
textAlign: 'right',
fontSize: 14,
color: '#FFFFFF'
}
})
export default FilmItem
Here's the view I'm trying to access
// Components/FilmDetail.js
import React from 'react'
import { StyleSheet, View, Text } from 'react-native'
class FilmDetail extends React.Component {
render() {
return (
<View style={styles.main_container}>
<Text>Détail du film</Text>
<Button
title={`Go to ${Home}`}
onPress={() => navigation.navigate(Home)}
/>
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
flex: 1,
}
})
export default FilmDetail
Upvotes: 0
Views: 775
Reputation: 78840
The error tells you what you need to know
Undefined is not an object (evaluating '_this.props.navigation.navigate')
It's referring to this line.
this.props.navigation.navigate("Details")
Obviously this.props
is an object, but this.props.navigation
is not, so this.props.navigation.navigate
will fail to evaluate. The reason why this.props.navigation
is undefined
is because you didn't pass a navigation
prop to your component.
const HomeScreen =({ navigation }) => {
return (
<Search/>
);
}
Here you've defined a HomeScreen
component that is receiving a navigation
prop, but the error you're getting is in your Search
component which does not have that prop. You can simply pass it in:
const HomeScreen =({ navigation }) => {
return (
<Search navigation={navigation}/>
);
}
...or if your component is really that simple, you can do:
const HomeScreen = Search;
...and let Stack.Navigator
pass the navigation
prop directly into your Search
component.
Upvotes: 1