Build a Fullstack Music App with Next.js Playing Songs State
A second version of this course released using Next 13+, but this course is great if you want to see another example fullstack project. We now recommend you take the Build a Fullstack App with Next.js, v2 course.
Transcript from the "Playing Songs State" Lesson
>> All right, let's keep moving. So now, we need to actually get some music in here and get things going. I think we actually need music inherit to get this next part working. So let's do that, so what we'll do before we continue working on the UI is try to get some music in here.
[00:00:22] Which means we're gonna have to get the data from somewhere and populate the songs and get them going. Luckily for us, we already set up the state to be able to do this. So what we're gonna do is head over to where you would add music, which in this case will be the playlist page.
[00:00:39] So pages/playlist/ID, so inside of here. And then we have the SongTable, right? So if you look at the SongTable, there's gonna be this big play button. So when someone clicks this button we want to add songs. That means, hey, I want to play this playlist. That's what that big green button is on the playlist.
[00:00:59] It's this one, that's what this button is. So if someone clicks this, they want to playlist. So that should send some active songs to the store. And if someone clicks an individual song that should send an active song and the playlist that that song belongs to to the store.
[00:01:15] So these are our two places where we actually want to update the state and get the songs going. And then inside of the player or the player bar, we can retrieve that state and now we can actually have some songs playing. So let's do that. So we'll just have to add some few click handlers on these buttons to actually get that going.
[00:01:35] And like I said, we did create those actions yesterday. So setting that up shouldn't be that difficult, so what we'll do is we'll go back to the SongTable. And we'll import those actions that we created from Easy Peasy. So we want to import from Easy Peasy here, and we want to import the use action.
[00:01:59] Or useStoreActions, sorry, useStoreActions. And at the top of here, we just want to get a reference to the setActiveSong action. And then also the one for setting the active. So one for setting active song, singular, one for setting active songs, plural. So we'll say, playSongs. I'll call it playSongs, and this is gonna be useStoreActions, like this.
[00:02:29] It's a hook, it's going to take a callback, you're get the store as an argument. Now all we gotta do is just return the action that we want. So for this one, I want to get the store.changeActiveSongs, like that. So I wanna get that action. And it's gonna freak out because TypeScript, so I'm gonna any that.
[00:02:52] So this is the plural one, I just want to get that changeActiveSongs thing that we made in our store. So if I go back to our store, just as a refresher, we made this changeActiveSongs here. So I'm getting a reference to this function, which, if you remember, it just takes in a list of songs and sets the active songs to that list of songs, that's all it does.
[00:03:12] Then I'm gonna do the same thing for the singular, setting an active song, and I'm just gonna call this setActiveSong. And this one's just literally getting rid of this. Okay, so now that we have that, all we have to do now is just attach this to some handler.
[00:03:43] So I'm just gonna make a function called handlePlay. So when you click the play button or you click a song, it's gonna run the handlePlay function. And it's just going to set the active song and the active songs, so the playlist. So let's say const handlePlay, and play is going to take in an active song, optionally, cuz maybe you did click on the song, maybe you clicked on the green button.
[00:04:11] So it's optional if you pass an active song or not. And then what it's going to do is to set those things. So first it's going to set the active song so whatever song you passed in, if you did. If you did not, we're gonna set it to the songs that we get in our props, 0.
[00:04:28] So the first thing in there, so start the playlist at the top. If you did not click on the song, instead you clicked on the green button, then start at the top, play the first thing in this list. But also we're going to set the active songs to all the songs, so this entire playlist.
[00:04:55] Then just hook up the handlers for the two places where you might click. The first one is gonna be on this big button, so we'll say onClick. If someone clicks this button, then we just wanna call handlePlay, With no argument. But if we pass it in like this, we're gonna get a bug because it's gonna pass in the event as an argument.
[00:05:16] But it's gonna think that event is an active song, it's gonna set it and now we're gonna have a bunch of trouble. So we're going to just proxy this with a callback and then call it without any argument. And then lastly, we're just going to add the onClick for the table, the whole table row, I think, for each song, Tr, where's it at?
[00:05:47] Yeah, this thing right here. So for each Tr here, we're gonna add onClick, and we're gonna do the same thing. We're just gonna say onClick, and then we're gonna pass in a song in this case, so we'll just pass an anonymous function here. We'll say handlePlay, and then we'll pass in the current song that we're iterating over, so that means you clicked on a song.
[00:06:12] And I wanna change this to pointer, I don't know why it cursor="cursor", it should be cursor="pointer". There we go. Okay, so now we got that, we can now go into our player bar and pull in the state and then we'll just pass it down as a prop to the player.
[00:06:39] And that way we can actually toggle whether we want to show the player or not if the song is active, that way we can do it there. So what we'll do is head over to the PlayerBar, and we'll pull in the state here, so we'll import some stuff from Easy Peasy.
[00:06:56] And we're gonna import a useStore, pretty sure it's just gonna be useStore. And like I said, all we're gonna do is is get the states, we don't need anything else. And we wanna get it here versus getting it in a player. Because like I said, we wanna be able to toggle whether or not we show the player controls and have to load up Holler.js and all that stuff unless there's an active song in the first place.
[00:07:22] And actually, I think it's useStoreState, that's what it's called. So useStoreState, and then we're just gonna go ahead and get the state. So I'll say songs. That's gonna equal useStoreState, like that. And it too takes a callback within state. And I'm gonna any. And for songs, it's just gonna be state.activeSongs, that's what we had in the store.
[00:07:47] That's all we gotta do, got the active songs. And then for the singular active song, we're just gonna call it activeSong. And we're just gonna take away the s, there we go. That's it. So now we need to fulfill a couple things. One, we got to pass in the props to the Player.
[00:08:19] It wants some songs. So we'll pass in some songs here, we got those. And it also wants an active song. So we'll pass that in as well. So we got those. And then we're gonna do some conditionals. One, I don't wanna render this artist Box that shows the name of the song and the artist if there's no song playing.
[00:08:41] So I'm just gonna conditionally render that. And I'm just gonna say, well, is there an active song or not? Is there an active song? If so, cool, yeah, we'll render this. If not, then just null, and don't render anything And we'll do the same thing with the player, we'll conditionally render this, is there an active song?
[00:09:13] If so, render that, if not, then null, don't render anything. And it look like its working, all of our control disappear because we don't have active song. Which is exactly what we expected, but now if I click on one of these, if I click this play button, it should set the active song state, which should put something on the page.
[00:09:32] So if I click this, you can see, I clicked on that, it brought it back. If I refresh and I click on a song, it also brings it back. So we know that it's picking up the state, Easy Peasy's working, the state's being propagated. We're reading the state, the conditionals are working.
[00:09:48] So now we just got to not hard code this song name and not hard code this artist name. So the way we do that is right here in the PlayerBar, let's get rid of where it says Song Name in this text. And we'll just say activeSong.name. And for Artist Name, it'll be activeSong.
[00:10:14] Artist.name. Cool, so if I click on this, you can see that it shows the current active song and the artist, there. The other way we could have handled this state was just using some hooks with a useContext and a provider and made our own thing. But like I said, it usually leads to performance issues.
[00:10:46] You get to the point where it's like, wow if you open the React Dev Tools, and it'll show you what is rendering and why it's rendering, you'll always see some context thing there. You'll like, everything is re-rendering because one thing in the context thing changed. So you have to write a very specific way.
[00:11:04] I think it's just not worth it. And then what's next is to actually play some music. So now that we actually have a song coming in on the player, we have songs, we have activeSong, we can actually play some stuff now. So we should be able to uncomment out this ReactHowler.
[00:11:20] So what we'll do is the first thing is we'll uncomment, like I said, ReactHowler, and we'll try to get all of this stuff working. So let me get rid of the sidebar, come here, save this. So right now we got the activeSong, got the URL, playing is set to whatever playing is.
[00:11:38] I think that might be the default that we need, let's see if it renders. If not, we gotta fulfill all the other stuff. So I'm gonna refresh this. Actually, mine is already playing. I wonder if you can hear.
[00:11:54] Cuz playing was set to true. So I refresh and then I'm gonna click on a song, elevator.
[00:12:05] Okay, yeah, so if you just render the ReactHowler with the minimal playing set to the playing state and and that active song URL in there, it should start playing. None of the seeking or any of that stuff is going to work because we didn't hook it up yet.
[00:12:17] So if you expect to see this moving or that to be right, it's not. We gotta do that next. That's the hard part coming up next, but it should play.