React - Value from API doesn't appear in View

Viewed 596

I'm very new to React Native and following a course where I meet this issue :

This component shows "TEXT" but doesn't show {film.title}

_displayFilm() {
  const { film } = this.state
  if (film != undefined) {
    return (
      <ScrollView style={styles.scrollview_container}>
        <Text>TEXT</Text>
        <Text>{film.title}</Text>
      </ScrollView>
    )
  }
}

I'm Using Atom in Ubuntu and use Expo Android App to see the result.

Another inconvenient I have is that I don't get logs from console.log() in Atom terminal that could have helped me for example to see complete json film object. The value "title is correct (use in another page of my app).

If anybody have an idea how to solve it, thanks a lot !

If useful, here is the complete file content :

// Components/FilmDetail.js

import React from 'react'
import { StyleSheet, View, Text, ActivityIndicator, ScrollView, Image } from 'react-native'
import { getFilmDetailFromApi, getImageFromApi } from '../API/TMDBApi'
import moment from 'moment'
import numeral from 'numeral'

class FilmDetail extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      film: undefined,
      isLoading: true
    }
  }

  componentDidMount() {
    getFilmDetailFromApi(this.props.navigation.state.params.idFilm).then(data => {
      this.setState({
        film: data,
        isLoading: false
      })
    })
  }

  _displayLoading() {
    if (this.state.isLoading) {
      return (
        <View style={styles.loading_container}>
          <ActivityIndicator size='large' />
        </View>
      )
    }
  }

  _displayFilm() {
    const { film } = this.state
    if (film != undefined) {
      return (
        <ScrollView style={styles.scrollview_container}>
          <Text>TEXT</Text>
          <Text>{film.title}</Text>
          <Text style={styles.title_text}>{film.release_date}</Text>
          <Text style={styles.title_text}>{film.backdrop_path}</Text>
        </ScrollView>
      )
    }
  }

  render() {
    return (
      <View style={styles.main_container}>
        {this._displayLoading()}
        {this._displayFilm()}
      </View>
    )
  }
}

const styles = StyleSheet.create({
  main_container: {
    flex: 1
  },
  loading_container: {
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    alignItems: 'center',
    justifyContent: 'center'
  },
  scrollview_container: {
    flex: 1
  },
  image: {
    height: 169,
    margin: 5
  },
  title_text: {
    fontWeight: 'bold',
    fontSize: 35,
    flex: 1,
    flexWrap: 'wrap',
    marginLeft: 5,
    marginRight: 5,
    marginTop: 10,
    marginBottom: 10,
    color: '#000000',
    textAlign: 'center'
  },
  description_text: {
    fontStyle: 'italic',
    color: '#666666',
    margin: 5,
    marginBottom: 15
  },
  default_text: {
    marginLeft: 5,
    marginRight: 5,
    marginTop: 5,
  }
})

export default FilmDetail

And the called API is here :

const API_TOKEN = "MY_API_TOKEN"

export function getFilmsFromApiWithSearchedText (text, page) {
  const url = 'https://api.themoviedb.org/3/search/movie?api_key=' + API_TOKEN + '&language=fr&query=' + text + "&page=" + page
  return fetch(url)
    .then((response) => response.json())
    .catch((error) => console.error(error))
}

export function getImageFromApi(name) {
  return 'https://image.tmdb.org/t/p/w185' + name
}

export function getFilmDetailFromApi(id) {
  const url = 'https://api.themoviedb.org/3/movie/' + id + 'api_key=' + API_TOKEN + '&language=fr'
  return fetch(url)
    .then((response) => response.json())
    .catch((error) => console.log(error))
}
2 Answers

I think you are missing a ? in before the api_key:

const url = 'https://api.themoviedb.org/3/movie/' + id + '?api_key=' + API_TOKEN + '&language=fr'

you need to fix the console, as it must be showing that the response is wrong in the console atm... HTH

I believe your apiFunction should be more like this:

export function getFilmDetailFromApi(id) {
    const url = 'https://api.themoviedb.org/3/movie/' + id + '?api_key=' + API_TOKEN + '&language=fr'
  return fetch(url)
    .then((response) => response.json())
    .then((responseJson) => {
        return responseJson;
    })
    .catch((error) => console.log(error))
}

Try this in your component:

this.state = {
    film: {}, //change the undefined
    isLoading: true
}

componentDidMount() {
    this.getMovie();
}


getMovie() {
    const movie = getFilmDetailFromApi(this.props.navigation.state.params.idFilm);
    if (movie.hasOwnProperty('id')) { //that means a movie was returned
        this.setState({ film: movie, isLoading: false });
    }
}

The text in _displayFilm is showing because you have already set film as undefined. So as long as the state doesn't change, the text will show. Change your _displayFilm:

_displayFilm() {
    const { film } = this.state
    if (film.hasOwnProperty('id')) {
        return (
            <ScrollView style={styles.scrollview_container}>
                <Text>TEXT</Text>
                <Text>{film.title}</Text>
                <Text style={styles.title_text}>{film.release_date}</Text>
                <Text style={styles.title_text}>{film.backdrop_path}</Text>
            </ScrollView>
        )
    }
}

Now the problem might be that you are not getting the right data. It is possible that your data is contained in response.data.data or response.data and not just in response. So by all means console.log(response) and inspect

Related