 Okay, so in this episode, we are going to focus mostly on the front end. You remember in the last one we ended up where we retrieved some data from an external API and we returned it to our React front end and we're just logging it here in the console. We've got a list of podcast episodes that match the user's search. So we were searching for Joe Rogan and we got a list of ten podcasts that mentioned Joe Rogan. And they return each a title and a URL. And actually I shouldn't be calling those episodes, those should be called podcasts. We haven't gotten the episodes for each podcast yet. So now we want to display those on screen. So I'm going to start here, I'm going to say podcast equals data. Let's go back and change this so that whenever we say episodes here, that's podcasts. Again, I'm going to have to stop and start my server to make that change. Alright, so now we've got our podcasts. And let's actually set this up so that we're saving that to state. And this looks right. I'm going to start with an empty array. We're going to call our set podcast function once we have that. So set podcasts to podcasts. So now it's being saved in state when we get a list of podcasts. And of course we want to show those on screen. So right now we've got a form container. Let's go ahead and add a podcast container. And we're going to say, not podcasts.data, it's just going to be podcasts. And it really wants to add that. Now we're going to map the podcast. Let's see what it wants us to return here. Okay, so if we have an array of podcasts, we're going to loop through that array. And for each podcast we're going to, right now it's returning a div called podcast with the podcast title. We don't have any images. We don't have a description. What do we want here? We actually, this is going to be links. And the link is going to display that podcast title. And it's going to have a URL of the podcast.url. I think that should work. Let's try it. We're going to search for Joe Rogan. Submit. And we get an error. Podcast.map is not a function. You were probably screaming at me when you thought me do this. Let's properly destructure that. And try again. All right. Now we've got this jumble of links. And let's take a look at them and make sure that our link is being displayed properly. Yes. So if we were to click on one of these, sure enough, it takes us to the RSS feed. Each child in a list should have a unique key prop, right? So in React, because there's some DOM manipulation happening, if you were to change the order of these things or whatever, it wants it to have a unique identifier so we can properly tie the right DOM element to the right data. So you need this key prop and we could just call that podcast.title. Now if we run that search, it's not complaining. Okay. So the next thing we want to do is we want to make this look better. And rather than add a bunch of custom styles, I'm going to use a component framework, CSS framework, and you may have heard of these or used them before, things like Bootstrap, Tailwind, et cetera. I'm going to use Material UI. I haven't used it much, but I'm curious to learn more about it. So we'll learn together. So let's go to their install docs. Default installation, NPM. Let's just stick with NPM. And I'm going to be installing this in the client folder. So let's paste that code in there. So what they are asking us to do is install Material as well as Emotion, which is a way of specifying CSS styles in React. So it looks like they give you options to use things like style components instead of Emotion if you want. I'm just going to go with the default and let's see what else they want here. They want us to install the Roboto font. So we'll do that. Then you can import Roboto into your entry point like this. So the entry point for our app is this app.js. So let's go ahead and import that there. What else do we want here? Icons, we won't worry about that yet. So I think that should be enough to install Material. Let's start our server back up here. Okay, seems like it's running. I don't think anything looks different, probably because we haven't used any of the components yet. So let's go back to the docs usage. Okay. So the way that Material works is it has its own set of components. So where we might have been using a button, it imports this button element. You notice the capital letter there to distinguish it. And it's got its own syntax for styling things and whatnot. So that's how we're going to use this. And since we've got a button, let's go ahead and just do it. So we're going to import that button. And where's our button? Let's change this and see if that did anything. Yep, we've got a button. It doesn't look like their button. Why not? They've got this variant contained. So that's a way of styling the button without having to write CSS. So now it looks like theirs, but nothing else matches because we haven't switched to a Material input or label component. So let's actually figure out what our options are for this button. We use their search box. There we go. We've got the contained or outlined variance of that button. So, all right. So here we go. They call it a text field. And if we click here, we can see the source code for importing that. So same as the button. Let's import the text field. Let's change this to text field. I'm hoping all of these things will apply. Text field is not defined. Oh, there we go. Okay. We've got a text field that's bigger than our button. Why is that? Let's take a look here. Sizes. Okay. Oops. Clicked on the wrong source here. Size equals small. So that's just a prop that we add to the component. Size equals small. And now our text field small. Okay. Now we need it to have that label like the last one did. And it looks like they're actually not even using a label DOM element. They're just adding it as a prop here. Label equals podcast name. So let's see if that is the case. Yep. And it's going off screen, but we'll worry about that second, which means we don't need this label here. I'm assuming that they will handle all the accessibility aspects of applying the label properly. So that folks with screen readers or whatnot can still see a label. Let's search for a label here. Label. Podcast name. Yep. It's in there. And for podcasts. Good. Okay. So they've automatically added a label, handled all the accessibility for us. That's great. Now let's figure out how to keep this thing from going off screen. So I noticed in here in the code. They've got this box element. And I think that's what they use for, if I remember right, for divs. For just like container elements. So we're going to import that box. And they've even got a prop for it that says component equals form. So it's going to turn it into a form. So we don't have any unnecessary DOM elements. That's great. So let's actually just start by putting that in here. And we'll transfer over our form attributes into this component. And let's see what we've got here out of the box. No validate, autocomplete off. You've still got our on submit handlers and our post. Let's first see if our search still works. It does great. So now let's style this thing. It looks like it's applying a margin to the text field root and a width to that text field. But we want the box itself to have a margin. It looks like they're specifying margin by these sizes here. And I want it to be a flex box. And I think I want anything for the text field root. I think I just want to apply this to my box. Okay. So it's no longer going off screen. There's no margins though on the text field. So let's go ahead and specify that with this SX property. And again, that is allowing us to write CSS within the component. So for this text field, I want just a horizontal margin. And the way that material does that is with MX, I believe. Let's do that. Actually, I think I just want it on the right, margin right. All right. So that looks kind of, I think, how we want it. Okay. So now we want to style the results themselves. Let's go back here. We actually just do an unordered list inside of here. And we're going to actually wrap this link with a list item. Our key needs to be on the first element inside of our loop here. So I'm going to move that. And now we've got a list of items. You can check that in our DOM, UL, a bunch of allies, and a bunch of links inside of there. And now let's figure out what material does to style list items, lists, basic list. Let's see. List and list item. We're going to add those to our imports. I don't think we want any of these other imports just yet. And so we're going to replace these allies with list items and this UL with a list. Let's see what that did. Okay. It's less ugly to me. It doesn't look too different, but that works. And maybe the last thing we want to do is just style those links, basic links. We'll just start with the basics and we can worry about some fancier styling later. The main thing is we just want to get everything into our material UI components where possible. And that's going to, it may seem simple right now because we're not doing anything fancy, but it may save us trouble down the road in terms of making sure everything looks the same and style the same and handles all the accessibility needs that we have. That allows for reactivity, compatibility with react, et cetera. So even though these are just some basic elements, it's worth getting them into this component library. So I'll replace this with a link. Now we have some links. They look a little bit better. So that's a good start for a visual interface to our app. Now I mentioned we would display some loaders and messaging and stuff like that, but I don't think I'm going to do that for this video. I'm going to keep it short. But the last thing I do want to do is just refactor this code a little bit. We've got everything displaying inside this one app function. And so it means if anything has to reload like when we're calling set state on podcasts, because podcasts is inside our app component, everything inside the app component refreshes and reloads. But we don't want to do that. We want to break these things out into separate functions for each functional component so that only that component has to be rendered. That'll help us out performance-wise. It'll also just make our code a little more organized. So let's go ahead and do some refactoring here on that. So we're going to have a function for form container and a function for results container. Let's use that convention that they're using where the capital letter means it's a component. So we're going to move the bits of UI that belong to the form into the form container component and the bits that apply to the podcast list into the results container component. So I'll go back down, got my podcast container, paste that in here. Of course I paste that in the wrong spot because I can't talk and type at the same time. Okay, this is how we're going to implement those. And we don't need this anymore. We don't need this. And our set podcast name needs to go up in there. And our podcasts, we want those to be at the top level of our app. But our podcast search function, we want to be in here. So we need to figure out how we're going to communicate back to this app what those podcasts are. And we're getting an error because this component, the results container is trying to use those podcasts. But it doesn't have them anymore because we broke them out into this separate function. So these functions are scoped only to the data inside of them. And so we need to be able to pass those podcasts into this component. So let's move this back into here. Sorry, into our app. And when we get those podcasts, we're going to pass them into our results container. So podcasts equals podcasts. But we don't have them. So we're going to need to define a function that says handle set podcasts. And we don't want to reuse the podcast variables. So we'll say podcast list, set podcast, podcast list. So all we're doing is we're going to receive the podcast from the form container, set them into state, and pass that state down to the results container as a prop. So the form container needs this handle set podcasts function. So we can call that function inside itself and that will trigger in here. So let's go do that, form container, handle set podcasts. Rather than set podcasts, we're going to say handle set podcasts, podcasts. So it's doing that. That's being logged to state. It's being passed down here. And so our results container needs a prop for the podcasts. So now if we do a search, we get our list. So let's go back and review what we've got here. We've got a form container component. It performs the search. When it gets results, it calls this handle set podcasts function, which is a prop that is passed down from our app right here. So when we call handle set podcasts, it's actually calling the function within here. Now that is setting state with our list of podcasts. And that list of podcasts is being passed down to our results container as a prop. So our results container has that list of podcasts. And we say if we have podcasts and the array has something in it, then loop through all the items in that array and return this list of items. So there you go. There's a much more componentized version of this app. So the very last thing I want to do, I promise, is split each of these components out into their own files. So we don't end up having this huge app with all kinds of different components we got to scroll through. So I'm going to make a components folder. Within that, I'm going to make a file for our form container, not JS, and a file for our results container, not JS. And I can already tell we're probably going to want to change these names later, but let's just get them in there. So this is our form container function. Put that in there. Our results container function. Put that in there. And we'll leave our app in here. But that means now we've got to import those into our app. And GitHub pilot already can tell it's missing those dependencies. And says it's not found because there are no exports. So the reason there are no exports is because we didn't say export. I'm going to say default function form container. Same thing with the results container. Does it not want the default? Sorry. And now we're going to get a bunch of errors that these components are not defined because they only exist here. So import them there, import them here. And of course import react. Save that. Now make sure everything's working. It is. And our code highlighting is telling us what we haven't really used here. So let's go ahead and remove any unnecessary imports from those files. And we're good to go. So this is sort of best practices for production scale front end web development. Not necessary, but a lot easier to work with. So I think that's a good place to stop for this tutorial. In the next one, I think we should get into the meat of what this series is all about, which is using AI. So we're going to do some AI transcription of one of these podcasts. Stay tuned.