Mosh React Tutorial (part 13)

source download

Now, let’s create the data structure to store list of movies, which comes in an array of objects:

First, we create GPMovieDataClass.js class component. We put this in utils folder.

Our test data list of movies will have genre objects. Many movies will have the same genres. So let’s build a unique genre dictionary first.
The genre dictionary will have the genre name as its key, and the genre object (name, _id) as the value.

We create private dictionary _genres:

Notice we also create private Map object data. This is so that each genre can point to the movies that belongs to this genre:

{ _id: “5b21ca3eeb7f6fbccd471814”, name: “Comedy” } –> [ {name: “Airplane”..}, {name:’Baseball’, …}, {…} … ];

We then execute buildGenres so that _genres dictionary is filled in and complete.
Each genre in _genres has an array. We place the specified genre movie in those arrays.

In the callback, we fill up the genre arrays with movies. When it has finished, we would have all movies with their genre objects as keys.

Now, one of the functionalities is to get all genre names.
We do this with function getGenres to return an array of genre names.

We also need our list of genres as objects:

Get all movies by genre name:

Finally, get all movies. We basically through every genre available, and get their movies.

movies.jsx

Incorporate GPMovieDataClass into Movies component

We first import it and then create an instance. We stick the movies data into it.

moviesData.getGenreAsArrayOfObjects() will return array of genre objects
moviesData.getMoviesByGenreName(genre.name) will return array of movies by genre name

We will be using them in our React code.

We use genres in our state object. We simply use getGenreAsArrayOfObjects to give our state’s genres an array of Genres to display.
Notice that by default, we initialize our state’s movies to all the movies.
State property showingArr maintains the array to be shown on the UI. We can’t just show ALL of the movies. We have to show the paginated portion of the movies.

movies.jsx

Notice paginateMovies function. All it does is that depending on which number you give it, it gives you the starting pagination page, and ending pagination page. What we need is the pageSize in order to calculate this:

movies.jsx

Then we simply return that paginated part of the movies array. Remember that movies contain all movies right now. We just paginate according to page number.
We give the paginated array to state property showingArr. This will let us show just the paginated pages.

In render, we use showingArr to display the movie data for this page:

movies.jsx

Thus, we always use showingArr to hold the movies that we’re showing on the page.

Displaying the Pagination links

So we create a Pagination component to display the links. The idea is that we need:

1) the total list of movies
2) page size

That way, we can calculate the total # of pages:

Once we have page count, we know how many links to display.

Then, we simply fill an array from 1 to pagesCount. This is to signal the page number the user have clicked. Once the user clicks it, it gives that page number back to movies component to render the movies for this particular page. The showingArr in movies will paginate and calculate it.

Then for each element in the array, we simply return a list item with a link in it:

We also give it isActive functionality. We compare if the currentPage number is the same as ours. If it is, we give ‘active’ to its class.
Also, notice we give a callback function onPageChange. If a user clicks this link, we give the number back to the parent component movies.jsx so that it can change its showingArr.

Changing Paginated Movies UI

If you want to change the paginated movies that are shown, simply give it a different page number and it will calculate the starting and ending pagination number for you. Remember to give the array back to showingArr so that render will work. We pass function handlePageChange into the prop of Pagination component as described above. When the user clicks a link in Pagination component, that number will come back to this function as page parameter. We then change our showingArr accordingly.

movies.jsx

Changing Genre

We need a selectedGenre property in our state object to keep track what genre the user have selected.

movies.jsx

Changing genre requires us to get all the movies associated with this genre. We use getMoviesByGenreName to get the movies by genre name.
We need to update our movies with this newly list of movies. This way, the total # of movies will appear correctly, and also paginateMovies depend on this movies array to show the paginated results. We then update selectedGenre to keep track of what genre we’re on.

Finally, all that is done, we update showingArr and paginate the new list of movies.

movies.jsx

Genre List

So remember in our GPMovieDataClass, we filter out all the unique genres from our movies test data. We then implemented getGenreAsArrayOfObjects
to get the list of genres as full objects. We pass this list into our ListGroup to render the genres via items.

We then map through the items and display the names and unique ids for these genres.

Notice we used defaultProps for property names. This is because its cleaner for us to specify the property names we’re looking for in the genre objects.

For putting ‘active’ in the className to specify the active selected genre, we already selectedGenre in movies component state object. That way, when we select a link here, it gives the genre name back up to movies component via onItemSelect. Movies component then puts the string into selectedGenre to keep track.

Type Checking

Notice in Pagination component, we have propTypes object that can let you specify the ‘type’ of the property. For example, in itemCount, we specify that it must be a number and is required.

This means that in Movies Component, if you do something like this:

You’ll get an error:

This ensures that we check the type of the prop we inject.

In order to use this, make sure you install and import prop-types.

You can also specify the default values you want your prop types to be:

in our case, we use textProperty and valueProperty prop passed in from Movies component to specify the property names to retrieve from each Genre object.
We give it a default to say that we should look for ‘name’ and ‘_id”. This can save space when you are putting all these props into components which makes it look messy: