Let the Music Render: a sample app demonstrating React component hierarchy & interaction — Part 2 of 4
At this point I haven’t actually created anything for my app to render, but I will get there. First, I want to write two functions I know I will need later on:
- a function to add a song from the catalog to the user’s playlist
- a function to remove a song from the user’s playlist
Since playlistSongs is a piece of state that belongs to the MusicPlayer component, all functions that can change that state must also belong to the MusicPlayer component. I start with the function to remove a playlist song:
This function takes in one argument — the song item that I want to remove from the playlistSongs array. To do this, I take the playlistSongs array that is currently held in state and filter it to exclude the song I want to remove. Then, using the setState function, I assign the new filtered array to the playlistSongs in state.
The function to add a song to playlistSongs is similar, but with an additional wrinkle. I want my users to be able to click a song in the catalog and add it to their playlist, but I don’t want any duplicate songs in the playlist if the user clicks the same card twice. My function needs a conditional statement to check if the song is already in playlist before adding it.
This function also takes in one song as an argument. But before I set the state, I use a conditional statement that uses the find method on the current playlistSongs array. If the find method returns a matching song, nothing will happen — the setState function will not be invoked, and the app will not re-render.
If the find method does not find any matches, my function will create a new array that includes songToAdd. I do this by using […] or the “spread operator”. By using the spread operator I am essentially telling the function “take all of the items from this existing array”. Then I append songToAdd, and use the setState function to assign the new array to playlistSongs.
Now I am finally ready to start my render() function. I know from my components diagram that MusicPlayer has two children, SongCatalog and YourPlaylist. Therefore, these are the two components that need to be included in my return value. Since a React component can only return one HTML element, we need to nest our two components in a single <div> element.
I also know that these two components will each need to access some of the MusicPlayer data and functions in order to do their jobs.
- SongCatalog is going to need the allSongs array from state
- SongCatalog also needs the addSongToPlaylist function, so that songs in that container can be added to the playlist when clicked
- YourPlaylist needs access to the playlistSongs array from state
- YourPlaylist also needs the removeSongFromPlaylist function, so that songs in that container will be removed when clicked
I give these components the access they need by “passing props”, which means that I will assign the data and functions as properties. The syntax for this is similar to assigning other HTML properties:
Now my MusicPlayer component is passing the correct properties to its two child components — but still nothing is going to happen on my page, because I haven’t defined those components yet. In Part Three, I cover how to set up these two containers and use these properties to generate a card for each song.