Refactoring React Components0:00
One of the keys to becoming really good at React is to embrace the refactoring mindset, move things around abstract components and be comfortable with things evolving and changing through the previous lessons. I've intentionally already moved things around, created components, move them from the same file to another file to show you that it's kind of part of the workflow when you're working with React. These changes can happen at the markup level.
of the workflow when you're working with React. These changes can happen at the markup level as you've seen up to this point, but once you start bringing state and logic, that state is also going to change morph and move around. Speaking of refactoring, I will go and clean up some of the demos we've done in the previous lesson. So I'll remove the count value.
we've done in the previous lesson. So I'll remove the count value and I'll do two small changes that I would do myself instead of importing react here directly. I would import the useState hook like so. And the other thing that I would do is like this function handleClick has a simple one line simple task. And in cases like this you can also inline the function instead of naming it here. And then in here I would go directly setIsLiked.
instead of naming it here. And then in here I would go directly set isLiked to the opposite of isLike so I don't have to have a named function, especially for this one line execution. So that's a pattern you'll see a lot in React inline functions and you could still, if you needed to do more thing in this function, have more things here. I think the more fluent you'll become with React and the more you will use these inline functions here. But there's nothing wrong with abstracting a function.
and the more you will use these inline functions here. But there's nothing wrong with abstracting a function at the top if you need to. Alright, let's go back like so and ooh I gotta not forget to remove the count and we can also remove the flex classes that were here for demo purposes. And so here's a like toggle component, nice and tight. Let's make sure that it still works and it show does. So I've mentioned that state in the React application will
Need Shared Liked State1:42
Let's make sure that it still works and it shows. So I've mentioned that state in the React application will morph and move around. Let's talk about this. Right now we've defined individual like toggles for each of the puppies. But if we zoom out a bit in the context of the app, there are components like this short list here that seem to hint that we need to share, dislike states with the rest of the application. Also, it feels like to me instead
with the rest of the application. Also, it feels like to me instead of having individual like toggles, we should have some sort of list of liked or not liked. Basically an isLiked array of puppy IDs instead of just a toggle that is true or false. So we need to do two things here. We need to modify the states to be an array of puppy IDs instead of just a true / false bool. And then we need to find a way to share this state.
of puppy IDs instead of just a true false bull. And then we need to find a way to share this state with the shortList and potentially other places in the application. Right now a likeStatus lives inside the likeToggle which itself lives inside the PuppyCard which lives inside the Puppy'sList, which eventually lives in the MainComponent right here alongside other components like the shortList that may need this shared state.
the main component right here alongside other components like the shortList that may need this shared state. And you've just heard me say a key term here, sharedState. What we've defined before in the like toggle is called a localState. This is literally inside a component localState just for that component. Now we need to create some states that is going to be shared between multiple components, the puppiesList, the shortList and maybe more.
between multiple components, the PuppiesList, the ShortList and maybe more. So how can I get the likeState out of the likeToggle that is inside the PuppyCard that is inside the PuppiesList and then pass it to something like the ShortList? Think about it. You've already seen how to pass data throughout a React application using props. Here we pass to the PuppiesList, the puppies array and then the PuppiesList receives it and pass a Puppy to the PuppyCard,
and then the puppies list receives it and pass a puppy to the puppyCard, which in turn returns the likeToggle. We pass the puppies data down through props and this is exactly how we can also share state between different components by passing them down through props. You might remember that I mentioned that props are immutable, they never change. And this is the key difference between state and props.
that props are immutable, they never change. And this is the key difference between state and props. In React, props are used to pass data throughout the application, state is used to modify the UI and then re-render components with new props. Here, because we need to share the state of the liked puppies between components that sit in the main component, the answer is to define the state. Here we'll use the useState hook just like we did before.
Create Liked IDs State4:09
The answer is to define the state. Here we'll use the useState hook just like we did before and then we're going to pass these states down to the components that need it. Alright, so let's define some state here. I will import the useState hook from React. And remember now we want our state to be an array of whatever puppy has been liked in the puppies list, not just an individual puppy. So we might call our state value likedPuppies.
not just an individual puppy. So we might call our state value likedPuppies. Uh, you know what just liked because we're going to type this multiple times and then our setup will be called setLiked. But now the key difference is instead of having a bool value here, we will have an empty array. If I hover over the liked value, you can see that it's typed as an array of any, any TypeScript, any can really be anything.
as an array of any, any type script, any can really be anything because we haven't specified what's gonna go in this array. Now we know that we want puppyIds that are going to be numbers and so I can specify this to the useState hook. Here's a new syntax for you. And here I can say that this useState is going to take an array of number. So here inside the useState I define the shape of the state value
So here inside the U state I define the shape of the state value and you can see that now it's set as an array of number. And so if I had a default of 1 and 3 it would be fine but if I had a string of a, it would instantly tell me that I'm probably doing something I should not. And you know what? We're gonna keep 1 and 3 as the default value just so we can test that some of the puppies are liked when we implement the ui. So our state lives up here at the top.
Pass State via Props5:26
of the puppies are liked when we implement the UI. So our state lives up here at the top and we're going to pass the state the value and the set to the component that need it. So the PuppiesList is definitely going to need that. And so I will pass the liked value as a liked prop and the setLiked value for the seller. Now if you remember we had set a type for the PuppiesList and liked is not part of it. So we'll quickly update this here.
and liked is not part of it. So we'll quickly update this here. Our puppies list now receives an array of puppy and it also receives a liked value, which is a number array and then a set liked function that takes that liked value and then doesn't really return anything. It's just a way to trigger a new value. But void here means that there is no return value. Now this would work but just like we can define our own types, we can also use a lot of react internal types.
Now this would work but just like we can define our own types, we can also use a lot of React internal types. If I hover the setState function, remember we have this dispatch setState action type and well we may as well use that. So this dispatch that we import from React and then setState action and you can think of these angle brackets as sort of function parameters. And then we want the type of the value which is
of function parameters. And then we want the type of the value which is number array here. And so now instead of reinventing the sort of shape of function value, we using exactly what React expect from the state set from the useState hook. Alright? And now because we pass them here, we need to also receive this two liked and setLiked so we can actually do something with them. So let's verify that the liked array, which should be one.
and set liked so we can actually do something with them. So let's verify that the liked array, which should be 1 and 3 actually was passed down here to the puppies list. So in the puppies list before mapping over the puppies array, I'll have an item here and go console.log(liked); And let's see if we can see this array of 1 and 3. And indeed we do. So we've passed the state value down the prop to the component, which is great.
And indeed we do. So we've passed the state value down the prop to the component, which is great. Alright, let's get rid of this and we'll continue handing the states down the component tree as we need. So liked equals liked and setLiked equals setLiked. Once again those are not part of the type we've defined here. So liked is a number array
of the type we've defined here. So liked is a number array and setLiked is the dispatch set state action. Perfect. And so again we are going to receive these values here, liked, setLiked so that we can one more time pass them down another component liked, liked, setLiked, setLiked, liked. And if at this point you start to feel like it's a lot of props being passed down, multiple components, you are right.
of props being passed down, multiple components, you are right. This is actually called prop drilling and I'll show you later, but there's a way to circumvent that in React. But also there's nothing wrong with doing this and it's quite explicit to see what data goes where and how it passed through the components. I feel like we've reached our final destination here in the like toggle where we are going to receive the liked.
Update LikeToggle Logic8:13
I feel like we've reached our final destination here in the likeToggle where we are going to receive the liked and setLiked and set the type to liked number and dispatch setState action number. And so now in the likeToggle, we are going to actually remove that local state that we had created because we are now going to implement the actual shared state the likeState passed down from the main component. So a liked value is an array of puppyIDs.
down from the main component. So a liked value is an array of puppy IDs. So we should probably also know about what puppy this toggle comes for and therefore I think we should pass to the liked toggle, also the ID or puppyId. But let's go with id And this is going to be puppyDoId. This isn't part of the existing type, but we'll fix that. We'll receive the ID as well. And the ID is a number, oops, forgot the comma here.
We'll receive the ID as well. And the ID is a number, oops, forgot the comma here. And so now we can use that ID and then compare it against the liked array and see if it includes it. And then if it does we can show the heart as liked and if it doesn't we can show the heart as unlike. So basically our replacement for the condition here is going to be does the liked array include the puppyId for this puppy for this likeToggle.
to be does the liked array include the puppyId for this Puppy for this likeToggle. So we could do the whole logic in here or we can do it before the return statement. Cons, is this Puppy liked equals, does the liked array include the id? And matter of fact, this is short enough that we can do it directly in here. So does the liked array include the puppyId? And let me just comment out the empty onClick here.
So does the liked array include the puppyId? And let me just comment out the empty onclick here because it's going to trigger an error. So because liked is one and three by default I'm expecting one and three to be pink. Let's check it out and yep, it's working. But now when I click on one of the puppies like toggle, nothing happens. And uh, of course I've removed the onclick. So we need to now fix that part.
And uh, of course I've removed the unclick. So we need to now fix that part. So unclick, what do we want to do? Let's try this inline directly basically correct if the puppies already liked, remove it from the like array and then otherwise add the puppy to the luxury. So we're going to make this comparison one more time here and if that's true, we are going to filter out this value and otherwise we're going to add it.
and if that's true, we are going to filter out this value and otherwise we're going to add it. I will try to write it without copilot helping me, which is going to be impossible if goAway liked includes the id goAway, I said. So remember to modify the liked value, we are going to use the setLiked setter. And so setLiked in one way we can remove this idea from the array is to filter it out. So liked filter
array is to filter it out. So liked filter and for each popId, so that filter just like array_map gives us the index of the array. So because it's an array of IDs, this is the popId, we want to keep all the ones where the popId is not the id. In other words, we check the entire liked array and keep everything that does not have the same id as the id that we currently have.
and keep everything that does not have the same ID as the ID that we currently have. And otherwise we also going to call setLiked and copilot has flashed it in front of your eyes already 10 times. But we can use the array spread operator here to spread the existing liked array and then add the ID as an index. It'll go at the end of the array, but that's not really a problem.
It'll go at the end of the array, but that's not really a problem. We don't need them to be sorted. So let's delete the comments and we're going to try this out. So we're gonna click the button. If the Idea is part of the array already, we remove it, otherwise we add it. We start with 1 and 3 by defaults. But I can add 2, remove 1,
We start with one and three by defaults. But I can add two, remove one, remove three, remove two as well. So now we have an empty array, it works. We've successfully passed the liked array and the setState function all the way from the main components down to the like toggle. So we've essentially recreated the same but more complicated way of toggling the like hearts. But this time we're going to be able to use that share state.
Refine Types and Homework12:11
but more complicated way of toggling the like hearts. But this time we're going to be able to use that share state and pass it to the short list that needs it as well. I wanna do a quick update to the types that we've used to be even more specific. So we're passing an array of numbers here, but if we were even more specific than this, what we wanna pass is an array of puppy IDs and literally an array of puppy. And then I can drill down to the ID field.
and literally an array of puppy. And then I can drill down to the ID field. So if at any time we were to change the IDs to be strings, uh, we could kind of follow along with that type. So let's go update the type in our puppies list. I'll select both of these instances and replace them with puppy_id. But this needs to be an array of puppy IDs. And then once again here I'll replace the number with puppy_id.
And then once again here I'll replace the number with puppyId. And I think there is one more place where we need to update this. Hey, and here the ID can also be a puppyId. So we puppyIdentifying every number here and I'll select this too and paste that as well. And I think we good to go. And I'm going to challenge you here and give you some homework before you watch the next video.
And I'm going to challenge you here and give you some homework before you watch the next video where I show the solution. I want you to try to implement by yourself the short list using the actual shared state that we've created for the liked puppies. So find a way to pass the liked pu state to the short list and then display a dynamic list, a real list of liked puppies that represent the puppies that are liked in that state array.
of liked puppies that represent the puppies that are liked in that state array. Good luck and I'll see you in the next one.
