Creating a movie website with GraphQL and React - part two
Tags: react, graphql, node, express
Published: 2018-04-09 16:20:24

---
title: Creating a movie website with GraphQL and React - part two
published: true
description: Create a movies web app using express, react, and graphql 
tags: react, graphql, node,express
cover_image: https://thepracticaldev.s3.amazonaws.com/i/ugl3fc8kpv87z2px34v7.png
series: Creating a movie website with GraphQL and React
---


In [part one](https://github.com/aurelkurtula/IMDBgraphql/tree/Graphql-api) we created the GraphQL API. Now we are going to create a react application that makes use of that API.

Before we move on, just because I thought it to be cool, we could use an HTTP client, like axios, to make requests to our GraphQL server! Check this out: 

```javascript
const query = `{
	newMovies {
	  id
    title
	}  
}`
const url = 'http://localhost:4000/graphql?query='+query;

axios.get(url)
  .then(res => console.log(res.data.data.newMovies))
```

If you are interested, you can see that setup in action by paying attention to the url changes when using the graphQL interface - we worked on in [part one](https://dev.to/aurelkurtula/creating-a-movie-website-with-graphql-and-react-25d4)

However, to make production easier and pleasant, instead of using an HTTP client there are GraphQL clients which we can use.

There are few clients to pick from. In this tutorial I am going to use the [Apollo Client](https://www.apollographql.com/docs/react/). Apollo provides a graphQL server as well but we already created that with `express-graphql` so we are not using that part of Apollo, but the Apollo Client, as the name suggests is the part which gives us the ability to write GraphQL in react.

## In a nut shell

If you want to follow along you should clone the repository from [github](https://github.com/aurelkurtula/IMDBgraphql/tree/Graphql-api), checkout the branch name `Graphql-api` and since we're going to focus on react side now, all the code is going to be writen in the `client` directory, which is the react application code. 

Clearly this is not a beginner's tutorial. If you don't know react but are interested in learning the basics I've writen [an introduction to it](https://dev.to/aurelkurtula/introduction-to-react-532).

First install the following packages. 

```
npm install apollo-boost react-apollo graphql-tag graphql --save
```

The game plan is to wrap our react app with an `ApolloProvider` which in turn adds the GraphQL client into the react props. Then make graphQL queries through `graphql-tag`.

At the moment, in `./client/index.js` you see this setup

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import './style/style.scss';
const App = () => {
  return <div>Hello World2</div>
}
ReactDOM.render(
  <App />,
  document.querySelector('#root')
);
```

First step, wrap the entire app with the `ApolloProvider`. The provider also needs a GraphQL client to pass to react.

```javascript
import { ApolloProvider, graphql } from 'react-apollo';
...
const client = new ApolloClient({
  uri: "http://localhost:4000/graphql"
});
ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider> ,
  document.querySelector('#root')
);
```

The `ApolloClient` requires a `uri` if the GraphQL server doesn't point at `/graphql`. So in our case leaving it out and just using `new ApolloClient()` would work

Now that we have access to the client we can make queries llike so:

```javascript
import { ApolloProvider, graphql } from 'react-apollo';
import gql from 'graphql-tag';
import ApolloClient from 'apollo-boost';

const AppComponent = (props) => {
  if(props.data.loading) return '<div>loading</div>';
  return <div>{props.data.newMovies[0].title}</div>
}
const query = gql`{ newMovies { title } }`;
const App = graphql(query)(AppComponent)
```

We wrap the `AppComponent` with `graphql`, we also inject the query into the props so then `props.data.newMovies` gives us the movie results. 

## Let's get started

Because the application we are building is bigger then the above example of displaying a single title, lets split it out. 

Start from `./client/index.js` 

```javascript
import React from 'react';
import ReactDOM from 'react-dom';
import ApolloClient from 'apollo-boost';
import { ApolloProvider } from 'react-apollo';
import { HashRouter, Switch, Route } from 'react-router-dom'
import NewMovies from './components/NewMovies';
import './style/style.scss';
const client = new ApolloClient();
const Root = () => {
  return (
    <HashRouter >
      <ApolloProvider client={client}>
      <Switch >
        <Route exact path="/" component={NewMovies} />
      </Switch>
      </ApolloProvider>
    </HashRouter>
  )
}
ReactDOM.render(
  <Root />,
  document.querySelector('#root')
);
```

Simple, a couple of routes. the imported component (`NewMovies`) don't exist yet but that's all the code required in `./client/index.js`. 

Again, all the components that we would ever use would be specified within the `Switch` component. Therefore the entire app is wrapped with in the `ApolloProvider`, exactly the same as in the nutshell section. 

## Getting top movies 

Let's create a file at `./client/components/NewMovies.js`, and start by importing the required packages 

```javascript
import React, { Component} from 'react'
import gql from 'graphql-tag'
import { graphql } from 'react-apollo'
```

Next, inject the `newMovies` GraphQL query results into the `NewMovies` Component

```javascript
class NewMovies extends Component {
...
}
const query = gql`
{
    newMovies {
        id
        poster_path
        title
    }
}
`
export default graphql(query)(NewMovies);
```

With that setup, an object array gets injected into the `NewMovies` component props and can be accessed by `this.props.data.newMovies`. Let's make use of them: 

```javascript
class NewMovies extends Component {
    Movies(){
        return this.props.data.newMovies.map(movie => {
            return (
                <article key={movie.id} className="movie_list">
                    <img src={movie.poster_path} />
                    <h1>{movie.title}</h1>
                </article>
            );
        })
    }
    render() {
        if(this.props.data.loading) return <div>loading</div>
        return this.Movies()
    }
}
```

There we have it. Things to note are

- The react component loads before the `newMovies` results are fetched. 
- graphql gives us a `loading` property which is set to `true` whilst data is fetched, and `false` when the data is ready to be used

Before we move on to another component, lets wrap the movie posters with an anchor so that we get more information when one poster is selected. 

To do so we'll use the `Link` component from the `react-router-dom` package.

```javascript
import { Link } from 'react-router-dom'

class NewMovies extends Component {
    Movies(){
        return this.props.data.newMovies.map(movie => {
            return (
                <article key={movie.id} className="movie_list">
                    <Link to={"/info/"+movie.id}> 
                        <img src={movie.poster_path} />
                    </Link>
    ...
```

Whenever a poster is clicked we are directed to `/info/1` for example. 

We need to head back to `./client/index.js` and add a router which catches that route. 

```javascript
...
import MovieInfo from './components/MovieInfo';
...
const Root = () => {
  return (
    <HashRouter >
      <ApolloProvider client={client}>
      <Switch >
        <Route exact path="/" component={TopMovies} />
        <Route exact path="/info/:id" component={MovieInfo} />
      </Switch>
      ...
```

Of course, that's the power of react routing ([covered here before](https://dev.to/aurelkurtula/introduction-to-react-router-ha)). 

## Let's work on `MovieInfo` Component

Start by creating the file at `./client/components/MovieInfo.js` then add the following:

```javascript
import React, { Component } from 'react'
import gql from 'graphql-tag'
import { graphql } from 'react-apollo'
class MovieInfo extends Component {
    render(){
        if(this.props.data.loading) return <div>loading</div>
        return (
            <div>{this.props.data.movieInfo.title}</div>
        )
    }
}
const query = gql`
{movieInfo(id: "284054") {
        title
}}`;

export default graphql(query)(MovieInfo);
```

It sort of works right? 

We are querying an `id` that we hard coded and that's not what we want, instead we want to pass an ID from our react component props to the graphql query. The `react-apollo` gives us a `Query` component that enables us to do that. 

```javascript
import { Query, graphql } from 'react-apollo'
class MovieInfo extends Component {
    render(){
        const id = this.props.match.params.id;
        return (
            <Query query={query} variables={{id}} >
            {
                (({loading, err, data}) => {
                    if(loading) return <div>loading</div>
                    return (
                        <div>{data.movieInfo.title}</div>
                    )
                })
            }
            </Query>
        )
    }
}
const query = gql`

query MovieInfo($id: String) {
    movieInfo(id: $id) {
        title
      }
  }
`;
```

Almost the exact same thing but with `Query` we are able to pass it variables. 

Now let's develop the rest of the component. Inside the `Query` return the following code 

```javascript
return(
    <div>
        <header style={{backgroundImage:  'url("https://image.tmdb.org/t/p/w500///'+data.movieInfo.poster_path+'")'}}>
            <h2 className="title">{data.movieInfo.title}</h2>
        </header>
        <article className="wrapper">  
            <p className="description">{data.movieInfo.overview}</p>				
            <div className="sidebar">
                <img src={"https://image.tmdb.org/t/p/w500///"+data.movieInfo.poster_path} className="cover_image" alt="" />
                <ul>
                    <li><strong>Genre:</strong> {data.movieInfo.genres}</li>
                    <li><strong>Released:</strong>{data.movieInfo.release_date}</li>
                    <li><strong>Rated:</strong> {data.movieInfo.vote_average}</li>
                    <li><strong>Runtime:</strong> {data.movieInfo.runtime}</li>
                    <li><strong>Production Companies:</strong> {data.movieInfo.production_companies}</li>
                </ul>
                <div className="videos">
                    <h3>Videos</h3>
                    {/* videos */}
                </div>
                    {/* reviews */}	
            </div>
                {/* credits */}											
        </article>
    </div>
)
```

As you can see we are trying to access query properties which we haven't requested. If you run that it will give you a 404 error as the requests fail. Hence, we need to update the query to request more then the `title` property:

```javascript
query MovieInfo($id: String) {
    movieInfo(id: $id) {
        title
        overview
        poster_path
        genres
        release_date
        vote_average
        runtime
        production_companies
      }
  }
`;
```

With that update and with the css that is going to be available in the git repository, the section we've been working on would look something like this:

![](https://thepracticaldev.s3.amazonaws.com/i/y57fdje3yerthywh3pkf.png)

As you can see in the code comments we need to add videos, reviews and credits on the page. 

## Adding videos

Remember the way we designed the GraphQL query in [part one](https://dev.to/aurelkurtula/creating-a-movie-website-with-graphql-and-react-25d4) gives us the ability to fetch the videos within the `movieInfo` query. Let's do that first: 

```javascript
const query = gql`
query MovieInfo($id: String) {
    movieInfo(id: $id) {
        ...
        videos {
            id 
            key
        }
      }
  }
`;
```

These videos come as an array - as sometimes there's more then one. So the best way to deal with these arrays is to create a separate method inside the `MovieInfo` component and let it return all the videos.

```javascript
class MovieInfo extends Component {
    renderVideos(videos){
        return videos.map(video => {
            return (
                <img key={video.id} 
                    onClick={()=> this.videoDisplay(video.key)} 
                    className="video_thumbs" 
                    src={`http://img.youtube.com/vi/${video.key}/0.jpg`}
                />
            )
        })
    }
    render(){
        ...
        {/* videos */}
        {this.renderVideos(data.movieInfo.videos)}
        ...                     
```

As we've covered in the first tutorial the `key` in the `videos` object refers to the youtube video ID. Youtube gives us the ability to use a screenshot image using that particular format (passed in the `src` attribute). also, as we previously mentioned, we took the ID exactly because we knew we need something unique for the `key` - required by React. 

When the user clicks on these thumbnail images I want to load a youtube video in the screen, hence `onClick={()=> this.videoDisplay(video.key)}`. Lets create that functionality.

The way we are going to implement this is by changing the state

```javascript
class MovieInfo extends Component {
    constructor(){
        super();
        this.state={
            video: null
        }
    }
    videoDisplay(video){
        this.setState({
            video
        })
    }
    videoExit(){
        this.setState({
            video: null
        })
    }
    ...
```

When the page loads `video` state is `null`, then when the thumbnail is clicked and `videoDisplay` is triggered, `video` state takes the youtube video `key` as a value. As we'll see, if the `videoExit` method is triggered, the `video` state resets back to `null`

Finally we need a way to display the video upon state change, so lets create another method. Just under the above methods, add this method:

```javascript
videoToggle(){
    if(this.state.video) return(
        <div className="youtube-video">
            <p onClick={() => this.videoExit()}>close</p>
            <iframe  width="560" height="315" src={`//www.youtube.com/embed/${this.state.video}` } frameborder="0" allowfullscreen />
        </div>
    ) 
}
```

Then simply have it render anywhere on the page 

```javascript
<div className="videos">
    {this.videoToggle()}
    <h3>Videos</h3>
    {this.renderVideos(data.movieInfo.videos)}
</div>
```

Again, if the `video` state is `null`, `{this.videoToggle()}` does nothing. If the state isn't null - if `video` has a key, then `{this.videoToggle()}` renders a video.

## Adding Movie credits and reviews

I decided to put the movie reviews and movie credits in their own separate component. Let's create the empty component files, import and use them inside the `MovieInfo` component and also update the query.

Inside `./client/components/MovieInfo.js` add these changes

```javascript
import MovieReviews from './MovieReviews'
import MovieCredits from './MovieCredits'

class MovieInfo extends Component {
...
{/* reviews */}
    <MovieReviews reviews={data.movieInfo.movieReviews} />	
    </div>
        {/* credits */}
        <MovieCredits credits={data.movieInfo.movieCredits} />				
</article>
}
...

const query = gql`

query MovieInfo($id: String) {
    movieInfo(id: $id) {
        ...
        movieReviews {
            id
            content
            author
        }
        movieCredits{
            id
            character
            name
            profile_path
            order
          }
      }
  }
`;
...
```

We get the data from the `movieReviews` and `movieCredits` query, we pass them to their respective components. Now we just quickly display the data

### Movie credits component

Add the following code to `./client/components/MovieCredits.js`

```javascript
import React, { Component } from 'react'
export class MovieCredits extends Component {
    renderCast(credits){
        return credits.map(cast => {
            return (
                <li key={cast.id}>
                    <img src={`https://image.tmdb.org/t/p/w500//${cast.profile_path}`} />
                    <div className="castWrapper">
                        <div className="castWrapperInfo">
                            <span>{cast.name}</span>
                            <span>{cast.character}</span>
                        </div>
                    </div>
                </li>
            )
        })
    }
  render() {
    return (<ul className="cast">{this.renderCast(this.props.credits)}</ul>)
  }
}
export default MovieCredits
```

Nothing new to explain from the above

### Movie reviews component

Add the following code to `./client/components/MovieReviews.js`

```javascript
import React, { Component } from 'react'
class MovieReviews extends Component {
    renderReviews(reviews){
        return reviews.map(review => {
            return (
                <article key={review.id}><h4>{review.author} writes</h4>
                    <div>{review.content}</div>
                </article>
            )
        })
    }
    render() {
        return(
            <div className="reviews">
                {this.renderReviews(this.props.reviews)}
            </div>  
        )
    }
} 
export default MovieReviews;
```

And that's it. This is how the credits, videos and reviews would appear.

![](https://thepracticaldev.s3.amazonaws.com/i/1x9u077agbcja9t9fr82.png)

## Conclusion

The full application, such as it stands can be found at the same repository, and you can view the [demo here](https://aurelsgraphql.netlify.com/#/). It has three branches [react-app branch](https://github.com/aurelkurtula/IMDBgraphql/tree/react-app) and the [master branch](https://github.com/aurelkurtula/IMDBgraphql) have the full code, each tutorial building on top of each other. Where as the [Graphql-api branch](https://github.com/aurelkurtula/IMDBgraphql/tree/Graphql-api) has the code covered in the [first tutorial](https://dev.to/aurelkurtula/creating-a-movie-website-with-graphql-and-react-25d4)