Search code examples
javascriptreactjsthemoviedb-api

Why my methods for React function components don't work


I am developing a project with Moviedb api. I created the movie list under the name Movie component. I make my api requests in this component. From the Movie component to the MovieInfo component, I send the release date of the movie and the genres of the movie via props.

But I cannot apply substring and map methods to these properties that come to me in the MovieInfo component with props.

class Movie extends Component {

state = {
    movie: [],
    loading: false,
    actors: [],
    directors: [],
    visible : 6 // This state is for how many actors rendered. 
}



componentDidMount() {
    this.setState({
        loading: true
    })

    let moviesEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}&language=tr`
    let creditsEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}/credits?api_key=${API_KEY}`;
    this.getMovieWithId(moviesEndPoint);
    this.getDirectorsAndActors(creditsEndPoint);
}

getMovieWithId = moviesEndPoint => {
    fetch(moviesEndPoint)
        .then(response => response.json())
        .then((movie) => {
            // console.log(movie);

            if (movie.overview !== "" && !movie.status_code) {
                this.setState({
                    movie,
                    loading: false
                })
            }
            else { // if have not turkish overview fetch this 
                let engEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}`
                fetch(engEndPoint)
                    .then(response => response.json())
                    .then((movie) => {
                        this.setState({
                            movie
                        })
                    })
            }
        })
}

getDirectorsAndActors = creditsEndPoint => {
    fetch(creditsEndPoint)
        .then(response => response.json())
        .then((credits) => {
            // console.log(credits)
            const filterDirector = credits.crew.filter(person => person.job === "Director"); // filter directors from all employees
            // console.log(filterDirector)
            this.setState({
                actors: credits.cast,
                directors: filterDirector[0].name,
                loading: false
            })
        })
}

render() {
        const { movie, loading, actors, directors, visible } = this.state
        const { location } = this.props
    return (
        <>
            {
                loading ? <Spinner /> : null
            }
            {this.state.movie ?
                <MovieInfo
                    movieInfo={movie}
                    actors={actors}
                    directors={directors}
                    searchWord={location.searchWord}
                    visible = {visible}
                    loadMore = {this.loadMore}
                    loading = {loading}
                /> : null
            }

            {
                !actors && !loading ? <h1>Film Bulunamadı! </h1> : null
            }

        </>
    )
}

}

This is the non-working code inside my MovieInfo component and my errors like this :

TypeError: Cannot read property 'substring' of undefined
TypeError: Cannot read property 'map' of undefined



const MovieInfo = ({ movieInfo, searchWord, directors, actors, visible, loadMore, loading }) => {

const editReleaseDate = (date) => {  //? Idk why doesn't work !
    // return date.substring(5).split("-").concat(date.substring(0,4)).join("/")
    return date

    // console.log(date)
    // return date;
}

return (

<Col sm={5} className="movieInfo p-4 animated fadeInRightBig">
                <p className = "movie-title" > {movieInfo.title} </p>
                <h5 className = "mb-4 text-warning">Yayınlanma Tarihi: <span className = "text-light">{editReleaseDate(movieInfo.release_date)}</span></h5>
                <h5 className = "text-warning">Açıklama</h5>
                <p>{movieInfo.overview} </p>
                <ProgressBar label={`IMDB: ${movieInfo.vote_average}`} animated now = {`${movieInfo.vote_average}`} min={0} max={10} />
                <h5 className = "text-warning mt-3">Türü: 

                {  //? Idk why doesn't work !
                    // movieInfo.genres.map((genre, i) => {
                    //     return <span key = {i} >{genre.name}</span>
                    // })
                }

                </h5>
                <h5 className ="mt-2 text-warning">Yönetmen:  <span className = "text-light">{directors} </span> </h5>
                <div> <i className="fas fa-film fa-5x"></i> </div>
            </Col>
)

Solution

  • You have 1 loading state for 2 api calls so once one is finishing it is telling the component that it is done loading even if the second has finished. I split it up into 2 different loading states, loadingMovie & loadingActors.

    class Movie extends Component {
    
     state = {
        movie: [],
        loadingMovie: false,
        loadingActors: false,
        actors: [],
        directors: [],
        visible : 6 // This state is for how many actors rendered. 
     };
    
    componentDidMount() {
        this.setState({
            ...this.state,
            loadingMovie: true,
            loadingActors: true,
        });
    
        let moviesEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}&language=tr`;
        let creditsEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}/credits?api_key=${API_KEY}`;
        this.getMovieWithId(moviesEndPoint);
        this.getDirectorsAndActors(creditsEndPoint);
    }
    
    getMovieWithId = moviesEndPoint => {
        fetch(moviesEndPoint)
            .then(response => response.json())
            .then((movie) => {
                // console.log(movie);
    
                if (movie.overview !== "" && !movie.status_code) {
                    this.setState({
                        movie,
                        loadingMovie: false
                    })
                }
                else { // if have not turkish overview fetch this 
                    let engEndPoint = `${BASE_URL}/movie/${this.props.match.params.movieId}?api_key=${API_KEY}`
                    fetch(engEndPoint)
                        .then(response => response.json())
                        .then((movie) => {
                            this.setState({
                                movie,
                                loadingMovie: false
                            });
                        })
                }
            })
    }
    
    getDirectorsAndActors = creditsEndPoint => {
        fetch(creditsEndPoint)
            .then(response => response.json())
            .then((credits) => {
                // console.log(credits)
                if (credits && credits.crew) {
                   const filterDirector = credits.crew.filter(person => person.job === "Director"); // filter directors from all employees
                   // console.log(filterDirector)
                   this.setState({
                       actors: credits.cast,
                       directors: filterDirector[0].name,
                       loadingActors: false
                   })
                } else {
                   console.log('bad credits');
                }
            })
    }
    
    render() {
            const { movie, loadingActors, loadingMovie, actors, directors, visible } = this.state;
            const { location } = this.props;
        return (
            <>
                {loadingActors || loadingMovie ? <Spinner /> :
                (movie.length && actors.length) ?
                    <MovieInfo
                        movieInfo={movie}
                        actors={actors}
                        directors={directors}
                        searchWord={location.searchWord}
                        visible = {visible}
                        loadMore = {this.loadMore}
                        loading = {(loadingActors || loadingMovie)}
                    /> : null
                }
                {
                    actors.length && !loadingActors ? <h1>Film Bulunamadı! </h1> : null
                }
            </>
        );
    }
    }