I am currently building my first react-native application, which is a simple clone of IMDB. I am using NavigatorIOS to manage state transaction and build my application as modular as possible.
The error occurs when I try to go to my Movie Component from my Library Component. The Library lists all the movies the user has stored and the Movie component takes simple takes an object and displays the information of the movie passed.
The peculiar thing is that I reuse my Movie Component from my Search Component and I am unable to reproduce the exception.
Library Component:
var React = require('react-native');
var Separator = require('../Helpers/Separator');
var Movie = require('../Movie');
var {
Text,
StyleSheet,
View,
ScrollView,
TouchableHighlight,
ActivityIndicatorIOS
} = React;
var styles = StyleSheet.create({
container: {
flex: 1,
},
rowContainer: {
flexDirection: 'column',
flex: 1,
padding: 10
},
name: {
color: '#48BBEC',
fontSize: 18,
paddingBottom: 5
},
year: {
color: '#48BBEC',
fontSize: 14,
paddingBottom: 5
},
description: {
fontSize: 14,
paddingBottom: 5
}
});
class Library extends React.Component{
selectFilm(selectedMovie){
this.props.navigator.push({
title: selectedMovie.Title,
component: Movie,
passProps: { movie: selectedMovie, canSave: false, isAuthenticated: true }
});
}
render(){
var movies = this.props.movies;
var list = movies.map((item, index) => {
return(
<View key={index}>
<View style={styles.rowContainer}>
<TouchableHighlight
onPress={this.selectFilm.bind(this, movies[index])}
underlayColor='transparent'>
<Text style={styles.name}>{movies[index].title}</Text>
</TouchableHighlight>
<Text stlye={styles.year}>{movies[index].year}</Text>
</View>
<Separator />
</View>
)
});
return(
<ScrollView style={styles.container}>
{list}
</ScrollView>
)
}
};
Library.propTypes = {
movies: React.PropTypes.array.isRequired
};
module.exports = Library;
Movie Component:
var React = require('react-native');
var Badge = require('./Badge.js');
var Library = require('./User/Library.js');
var Separator = require('./Helpers/Separator');
var api = require('../Utils/api');
var {
StyleSheet,
Image,
Text,
View,
ScrollView,
TouchableHighlight,
AsyncStorage
} = React;
var styles = StyleSheet.create({
container: {
flex: 1
},
buttonText: {
fontSize: 18,
color: 'white',
alignSelf: 'center'
},
rowContainer: {
padding: 10
},
rowTitle: {
color: '#48BBEC',
fontSize: 16
},
rowContent: {
fontSize: 19
},
buttonText: {
fontSize: 18,
color: '#111',
alignSelf: 'center'
},
button: {
height: 45,
flexDirection: 'row',
backgroundColor: '#758BF4',
borderColor: 'white',
borderWidth: 1,
borderRadius: 8,
marginBottom: 0,
marginTop: 10,
alignSelf: 'stretch',
justifyContent: 'center'
}
});
class Movie extends React.Component{
componentDidMount() {
AsyncStorage.getItem("token").then((value) => {
this.setState({"token": value});
}).done();
}
getRowTitle(title){
return title[0] ? title[0].toUpperCase() + title.slice(1): title;
}
getTitle(item){
return item[0] ? item[0].toUpperCase() + item.slice(1) : item;
}
handleSubmit(){
api.addMovie(this.state.token, this.props.movie)
.then((res) => {
console.log(res);
if (res === 'Film already exists') {
alert('Film already exists');
} else {
alert('SAVED');
}
});
}
handleDelete(){
api.deleteMovie(this.props.movie.imdbID)
.then((res) => {
this.props.navigator.pop();
});
}
render(){
var showSave;
if (this.props.isAuthenticated) {
showSave = (
this.props.canSave ? <TouchableHighlight style={styles.button} onPress={this.handleSubmit.bind(this)} underlayColor="#48BBEC"><Text style={styles.buttonText}> SAVE </Text></TouchableHighlight> :
<TouchableHighlight style={styles.button} onPress={this.handleDelete.bind(this)} underlayColor="#48BBEC"><Text style={styles.buttonText}>DELETE </Text></TouchableHighlight>
);
}
var movie = this.props.movie;
var topicArr = ['director', 'year', 'rated', 'plot', 'country', 'awards', 'imdbRating'];
var list = topicArr.map((item, index) => {
if (!movie[item]) {
item = this.getTitle(item);
}
return (
<View key={index}>
<View style={styles.rowContainer}>
<Text style={styles.rowTitle}>{this.getRowTitle(item)}</Text>
<Text style={styles.rowContent}> {movie[item]} </Text>
</View>
<Separator />
</View>
)
});
return(
<ScrollView style={styles.container}>
<Badge movie={this.props.movie} />
{list}
{showSave}
</ScrollView>
)
}
};
Movie.propTypes = {
movie: React.PropTypes.object.isRequired
};
module.exports = Movie;
Search Component:
var React = require('react-native');
var Movie = require('./Movie');
var api = require('../Utils/api');
var {
Text,
View,
TextInput,
TouchableHighlight,
StyleSheet,
ActivityIndicatorIOS,
AsyncStorage
} = React;
var styles = StyleSheet.create({
// Styles
});
class Search extends React.Component{
constructor(props){
super(props);
this.state = {
title: '',
isLoading: false,
token: ''
}
}
componentDidMount() {
AsyncStorage.getItem("token").then((value) => {
this.setState({"token": value});
}).done();
}
handleChange(event){
this.setState({
title: event.nativeEvent.text
});
}
handleSubmit(){
var isAuthenticated = this.state.token !== null ? true : false;
this.setState({
isLoading: true
});
api.findMovie(this.state.title)
.then((res) => {
if (!res.Response) {
this.setState({
error: 'Movie not found',
isLoading: false
});
} else {
this.props.navigator.push({
title: res.Title,
component: Movie,
passProps: {movie: res, canSave: true, isAuthenticated: isAuthenticated}
});
this.setState({
isLoading: false,
error: false,
title: ''
})
}
});
}
render(){
var showErr = (
this.state.error ? <Text>{this.state.error}</Text> : <View></View>
);
return(
<View style={styles.mainContainer}>
<Text style={styles.title}>Search for a movie</Text>
<TextInput
style={styles.searchInput}
value={this.state.title}
onChange={this.handleChange.bind(this)} />
<TouchableHighlight
style={styles.button}
onPress={this.handleSubmit.bind(this)}
underlayColor="white">
<Text style={styles.buttonText}> SEARCH </Text>
</TouchableHighlight>
<ActivityIndicatorIOS
animating={this.state.isLoading}
color= "#111"
size="large">
</ActivityIndicatorIOS>
{showErr}
</View>
)
}
};
module.exports = Search;
Here is the application flow of my app:
Any help would be greatly appreciated.
Finally figure it out!
Silly mistake from my part.
The solution was to remove the requirement for the Library Component from the Movie Component. Once I deleted that line the error was gone. It appears that you cannot require the same component you are transition from, if you do you're code will break.
I recevied this error because I registered the component twice.
AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With