Identifying Repetitive Markup0:00
Let's take a look at how we can take the very repetitive markup from the puppies list and turn it into a data-driven ui. Okay, so let's go in the puppies list. We've created last lesson and so we've got an ordered list and inside of it, a list item for each individual puppy. And if I select one of them, you'll see all the others will get selected because they have the exact same classes.
you'll see all the others will get selected because they have the exact same classes. These are the same blocks of HTML. And the only thing that changes is the data, like the image, the name, the trait and stuff like that. And it makes sense. We want consistent UI for each of these cards. And maybe the only thing that changes is the little heart which can be liked or not liked. Everything else is the same.
which can be liked or not liked. Everything else is the same. When you see repeating markup like this, your brain is probably screaming at you to do something about it. I wouldn't resort to creating a component right away for this, but your first point of attack should probably be a loop of some sort. So if you come from the Laravel and Blade world, you might want to use something like @foreach.
So if you come from the Laravel and Blade world, you might want to use something like @foreach $puppies as $puppy and maybe if you come from view, you might want to do something like livewire four. And so I hear you ask what is the equivalent in JSX to do that? And well, JSX is not a templating language, it is just a JavaScript syntax. So you sort of need to use JavaScript.
JSX as JavaScript Arrays1:20
it is just a JavaScript syntax. So you sort of need to use JavaScript and whatever it allows you to do to iterate through some data. All right, let me explain what I mean when I say just JavaScript. Remember that JSX is just a series of React createElement function calls behind the scenes. Something like React createElement ul, let's not worry about the attributes or props.
Something like react.createElement ul, let's not worry about the attributes or props. So no. And then essentially we have a series of children and these are expressed as an array. So inside here we have react.createElement LI null and let's go like, yep, friskIt and then we have Chase and so on. This is really what you're indirectly writing when you're writing JSX. So if I was to take friskIt here, uh, copy
when you're writing JSX. So if I was to take frisket here, uh, copy that in my clipboard and remove the rest and inside the ul I would have frisk. I just need to import react at the top you can see that my first li item now is just the string of frisket in this grid. Like I said earlier in the course, it really helps when you look at JSX to think of the underlying JavaScript output.
it really helps when you look at GSX to think of the underlying JavaScript output or at least the sort of data structure. So we have an element and then an array of children. And this is the key term here, array. We are working with JavaScript arrays For each item, we are outputting a chunk of JSX. And so if we want to iterate over data in JSX, we can use array methods like map or filter to transform the data and output whatever we need.
Creating the Puppies Data2:41
we can use array methods like map or filter to transform the data and output whatever we need. All right, let's get rid of this and we need some data that we can iterate through. So let's go const puppies = and set an array. And instead of doing it manually, let's use AI here. So I'll ask co-pilot to extract the data from these puppies into the puppies array at the top. Let's see what happens. I think that should work. Okay, and it's suggesting something that is exactly
Let's see what happens. I think that should work. Okay, and it's suggesting something that is exactly what I was hoping for. Let's grab this array of data and we will place it here. Now I just wanna slightly modify this data. I want the description field to be called trait instead and we're not going to use the isLike functionality just yet. So let's remove that. And also the image should be imagePath.
Rendering with map()3:28
So let's remove that. And also the image should be image path. Alright, perfect. So we have an array of objects that have an ID, name, trait, and image path, and we have six of them. And so now let's try using array methods to iterate over this data and output JSX. So {} to enter a JavaScript expression. And we are going to take our puppies array and use one of the array methods.
And we are going to take our puppies array and use one of the array methods. You can see all these JavaScript methods. We are going to use the map method. The map method takes a callback function and it gives you the index or the puppy here. And so we want to transform this puppy, which is literally a slice of the array into a list item with all the classes. What is really going to happen is react.createElement, no props.
What is really going to happen is react at createElement ally, no props and let's pass the puppy that name. And when I save that, because we are iterating over the whole puppies array, I'm expecting six ally items with just the puppy name. And this is precisely what happened. We have our anorList and then six ally items. But life really is too short to write react elements with createElement.
But life really is too short to write React elements with createElement. So instead we can simply return JSX because it's multiple lines, I'm adding parentheses and I will grab the first li item and move it up. So eslint is very angry at me, but if we look at the UI, we have six cards, one for each puppy and obviously because it's still static markup, we are always outputting the same name,
because it's still static markup, we are always outputting the same name, uh, image, et cetera. But as you can imagine, this is very straightforward to fix. We receive the $puppy here in the callback function. And so all we need to do is go and replace the static markup with puppy data like $puppy->name, $puppy->trait and so on. But before I do this, I need to fix this lint error
Adding Unique Key Props5:20
puppy dot trait and so on. But before I do this, I need to fix this lint error that is burning my eyes and if I hover, it's going to tell me that I'm missing a key prop. You may have noticed before there was an error in the console and if I look at it, it is telling me the same. Each child in the list should have a unique key prop. This key is something that's required by React internals to keep track of who is who in the list.
This key is something that's required by React internals to keep track of who is who in the list. So that might seem overkill for a normal static list, but it makes a lot more sense when you start adding, removing or reordering list items. And really this concept of key is not unique to React. So in view, I believe there's also keys for list items and also in Livewire for example. So inside our list, which is inside the .map() here, the first element here needs a key.
So inside our list, which is inside the dot map here, the first element here needs a key. And typically you want something unique, a unique identifier. Quite often, and this is the case for us here, the data you're looping through might have an ID. Here we have puppyId, which is perfect for the use case. Assuming every ID is unique, ESLint has backed off and if I refresh the page, we will not have any errors in the console.
and if I refresh the page, we will not have any errors in the console. Now, quick but important aside here, you might know that the array_map also gives you a second argument, which is the current index in the iteration through the data. So here, if before the image uh, outputs the index, we should have 0, 1, 2, 3 and so on. If your data doesn't have an ID field, you might be tempted to use this index for the unique keys,
If your data doesn't have an ID field, you might be tempted to use this index for the unique keys, but you should not do this because if the list changes, if you add remove items or reorder them, the index will change with it. And so React will lose track of who's who and it's not gonna work. All right, something to keep in mind. So let me get rid of the index and we don't need it up here. And so now we're going to replace our static data.
So let me get rid of the index and we don't need it up here. And so now we're going to replace our static data with the data from the puppy. So the alt tag here can be puppy.name, the image source can be puppy.imagePath. Yes, let's take a look. And yep, that's definitely taking shape, although every card still says Frisket, mother of all pups, easy fix. We are gonna go here and go puppy.name once again.
of all pups, easy fix. We are gonna go puppy.name once again. And here is the character trait puppy.trait. And so now all our cards should have the correct image name and trait and they do fantastic. There is one little detail if we look here, all the hearts are unlike, which is very sad. Uh, our static markup had some of the dogs like Chase and Leah liked. And so the way that's implemented is in this SVG icon you.
Conditional Like Styling7:51
and Leah liked. And so the way that's implemented is in this SVG icon you can see a class name here and this is the unlike status. It has a stroke slate-200 and then on hover slate-300 color. And if I scroll down for another one, here's a liked one. You can see that it has a fill pink-500 and no stroke. And just like that you've entered the vast world of dynamic styling. For now, we are going to use the absolute simplest way to handle this again using JavaScript.
For now, we are going to use the absolute simplest way to handle this again using JavaScript. I'm going to copy the Tailwind classes that are specific to the like status. And matter of fact, we don't really need this lucid and lucid heart. These are because the icon comes from lucid.dev. And matter of fact, if I search for the heart, you will see that this is the icon that we're using. And while I'm here, the good news is this library has GSX.
that this is the icon that we're using. And while I'm here, the good news is this library has GSX version of this components. So you can see that you can import the component and then literally use the hard components. We're not gonna do that right now, but we'll definitely get round to it. Alright, so I will copy these two classes and then inside the dot map here we go find the SVG and we'll get rid of these classes that we don't need.
and then inside the dot map here we go find the SVG and we'll get rid of these classes that we don't need. And essentially we want to output these classes if the puppy is not liked and the ones I have in my clipboard, if the puppy is liked, we will make this truly dynamic and interactive in a future lesson. But for now let's have a JavaScript expression and let's say we want the second puppy here, chase to be liked.
and let's say we want the second Puppy here, chase to be liked. Chase has a puppyId of two, so I can check if puppy.id equals two question mark. We want to have in a quotes my classes that I've pasted and otherwise we want to have the other classes. Let me put that on multiple lines so it's super clear. We check a condition and if it's true we output these classes and if it's false, we output those classes.
and if it's true we output these classes and if it's false, we output those classes. Again, no templating synthetic sugar. We are just using JavaScript to achieve what we want to do. So now I'm fully hoping that puppyId of two AKA Chase is going to be liked and indeed he's what a good boy. Alright, so our puppiesList is in good shape except we still have the hardcoded puppies right after. So what I wanna do is collapse my listItem inside the map
still have the hardcoded puppies right after. So what I wanna do is collapse my list item inside the map so we see clearer. And then I'm going to delete completely all the other ally items. So we are just left with our one list item that we are iterating over. And for each item in the puppies array, we are outputting the same block of HTML with the appropriate data and that my friends is very cool.
we are outputting the same block of HTML with the appropriate data and that my friends is very cool.
