Let the Music Render: a sample app demonstrating React component hierarchy & interaction — Part 3 of 4

In Parts 1 & 2, I created the top-level MusicPlayer component for a sample app that will demonstrate how to design basic playlist functionality.

MusicPlayer’s render function includes two child components: SongCatalog and YourPlaylist. Since both of these components will eventually contain SongCards, I think of them as “container components”. In this post, I will demonstrate how to set up each of these containers.

I will start with my SongCatalog container, which will have two functions

  • A function that takes in the allSongs array and generates a SongCard for each item
  • A function that returns a single HTML element, as required for all React components

First, I write my createSongCards function. My function needs to go through every song in the allSongs array and return a SongCard component for each one. I haven’t yet defined what the cards will look like, but I know what data they will need.

First I use the map function on allSongs. Remember that the allSongs array is a piece of state from MusicPlayer that I passed to the SongCatalog as “props”, aka properties that are inherited from parent to child.

I don’t want my users to see an array of song data; I want them to see an HTML card for each song. The map() method is ideal for this use case; it allows me to go through every item in an array and transform it into a new form. My createSongCards() function goes through every song and for each one it returns a SongCard component with three properties:

  • the song object, which includes the name, title, year, and image for the song
  • the song key, which is a unique ID number for each song
  • the addSongToPlaylist function, that I defined in MusicPlayer and passed to SongCatalog as a prop.

My users will click on a SongCard in order to add it to the playlist, so the SongCard component needs access to the function. Just like I passed this function as a prop from MusicPlayer to SongCatalog, I need to pass it again from SongCatalog to SongCard.

Notice that when passing the addSongToPlaylist function to SongCard, I have renamed it to the more generic-sounding clickSong. I will go into detail about why I have done this in Part 3, when I build the SongCard component.

Now that I have a function to generate the cards, I need to include them in my render() function for this component. For this SongCatalog container, the render() needs to include:

  • The header “HIT SONGS OF THE EIGHTIES!”
  • The divs that provide the column/ row structure for the container
  • A SongCard for every song in the allSongs state, as defined in my createSongCards() function

With my SongCatalog built out, I can turn to the YourPlaylist component. YourPlaylist also has a function called createSongCards(), which is nearly identical to SongCatalog’s function, but with two important differences:

  • I pass in playlistSongs, instead of allSongs
  • I pass in removeSongFromPlaylist(), instead of addSongToPlaylist()

Notice again that I have renamed the function that I am passing to the card. MusicPlayer passed a function to YourPlaylist called removeSongFromPlaylist(). YourPlaylist passes that same function down to SongCard, but renames it to clickSong(). The reasons for this will be more clear when I build out SongCard in Part 4.