Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Invariant Violation: Element type is invalid: expected a string but got:object. Check the render method of 'NavigatorIOS'

Tags:

react-native

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:

Application Flow Any help would be greatly appreciated.

like image 316
gonzalovazzquez Avatar asked Dec 24 '15 21:12

gonzalovazzquez


2 Answers

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.

like image 126
gonzalovazzquez Avatar answered Oct 06 '22 22:10

gonzalovazzquez


I recevied this error because I registered the component twice.

AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp);
like image 26
Natus Drew Avatar answered Oct 07 '22 00:10

Natus Drew