Vue 3 Fundamentals

Vue 3 Fundamentals Emitting Custom Events Exercise

Learning Paths:
Check out a free preview of the full Vue 3 Fundamentals course:
The "Emitting Custom Events Exercise" Lesson is part of the full, Vue 3 Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:

Students are instructed to build out components as they see fit, whether receiving data from the parent or keeping it at the top level. Ben then walks through a possible solution to the exercise and answers some student questions. Student questions covered in this segment include having the favoriteCharacter function in a separate module, how the data gets into the favoritesList variable.

Get Unlimited Access Now

Transcript from the "Emitting Custom Events Exercise" Lesson

[00:00:00]
>> So now that you have this equipped or this new knowledge the exercise now is to kind of continue on your component exploration journey. And now you have basically the opportunity to architect your components kind of however you see fit. Do you want to go ahead and just have these display components that received data from the parent.

[00:00:19] And then if it makes changes emit that upwards or do you want to just keep everything at the top like you can figure out how you want to play around with that and see what works well for you All right, and we're back. So, one of the questions that came up during the exercise is people were playing around.

[00:00:39] And what they notice is, is that if you mutate the prop, everything does seem to work. So in other words, if you're in here, for example, and we said this.user.name, right, equals let's do Dominique. Okay, again, it will technically work. The principle I kind of want to kind of stress here, it's not so much that a question of whether or not it works or not, but more so that.

[00:01:07] When it comes to best practices for architecting apps, you want to keep it as easy as possible to debug what's wrong. This is why I'm also a big fan of when you have error reporting, or for example, we talked about styling later, but when we go too far in terms of our optimizations of like, well, it's easier to just do this right.

[00:01:29] It can make it tricky to track where things are happening. And so when it comes to UI, a lot of it ends up boiling down to where's your source of truth. And when you allow your codebase to start, sort of messing with that source of truth in different places, all of a sudden becomes a lot trickier to figure out why and when something happened.

[00:01:47] Whereas if you follow this pattern of emitting for children to parent, you'll always know that if in the future the user has a bug where this list for example is broken. You'll know that basically you probably should be looking at the parent and basically, you probably ought to solve it just off that alone.

[00:02:03] But if you allow the mutation to profit elsewhere all of a sudden that guarantee becomes far less likely, it's because you just don't know what's happening. So I always err on the side of keeping it easy when it comes to maintenance and debugging. Okay, so let's take a look at this exercise, shall we, okay That's all I want to know.

[00:02:28] Okay, perfect. So I'm gonna do is I'm gonna open up my atla forum, actually just good, okay. So atla forum, you great, refresh, cool, okay. So a good component to kind of illustrate this is going to be the favoriting button. Because we can see here that inside of app.view, we're actually managing our favorite list here at the very top.

[00:03:00] And so let's go ahead and create that favorite list component. So favorite list, great. Actually, what I think favorite characters is actually a bit more accurate. Favorite characters, great. And then I realized though actually wait, I misspoke rather than the favorite characters, we actually wanna create individual character cards.

[00:03:20] That's what we want, so let me rename this now to CharacterCard. And so, what we have here now, what I did earlier in case when people see that this is sfc code extension, so are not an extension. It's one of the shortened cards. So it's a shortcode that I customised so that when I type SFC for single file component, it will tell me my building watch me.

[00:03:45] Okay, so what we have here is we have this HTML that we basically want to refactor, which is what we are looping right here. Okay, so I'm gonna go ahead and actually just copy this as a div as a list item. Let's just do it as a div.

[00:04:05] Actually, this will be cleaner so that it doesn't have to be in the list. So we'll have a div and the div will contain all this stuff. Now, we need to move some functionality over though. So here's our placeholder. We need to move the favorite character functionality. Okay, and I think we need a prop, because we need to actually know what character we're rendering.

[00:04:35] So the character this case again will be a type object and so I'm not gonna actually break down the individual properties. And then that way we can get character that name and then for now let's not worry about the dysfunction because this will break and then that's it, okay.

[00:04:53] So to prove that this works, we're going to go ahead and import our character card. And then drop that here and then we're gonna use it inside of our placeholder. And we'll pass in the character as a prompt. So this is reusing all the stuff that we did earlier.

[00:05:19] Okay, everything is appearing as expected. Now the difference here though is that this favorite character functionality doesn't work because, guess what, this card does not care about its responsibility is not to track the favorite lists. So to the point of what I was talking about earlier you can theoretically pass favorite list as a prop to this component.

[00:05:40] And then you could have theoretically the component update favorite lists. But again, that starts to convolute the scope of the data and how it's being owned. That's not his goal. It's goal is to say, hey, I'm gonna show a card of my characters. And by the way, when someone clicks the favorite event, I will go ahead and tell the parent of whatever context I'm in, that the user decided they wanted to favor this card.

[00:05:59] Whatever you do with that, that's up to you. So what we gotta do here is we'll define our emits. Call and we'll just call it so we'll keep it simple actually, because it emits are scoped to this specific component, which is call it a favorite event. This is what's happening.

[00:06:15] So now that we have the favorite event, we can say, okay, well, when this happens, this.emit, what event are we emitting? It's called favorite, but more importantly, actually, what we can do is we can actually pass in an argument to our emitted function, which is this .character. So we can save that and then this time now you can click here to favoriteCharacter, okay, great.

[00:06:49] Now that we have this we can come over here and then we can say yes so on the character card we have this favorite event that's gonna happen and when it does we can say addFavorite character And so if you take a look now, let's update this method called addFavorite character.

[00:07:09] And what you end up getting because you're passing it as an argument is a payload, basically you can rename it whatever you want. But generally speaking, we call it a payload because this is coming from the event. So again, the way this is connected to show the side by side, this tournament admits this as the event name.

[00:07:26] And this year the second argument will basically be the payload. So it's generally frowned upon for example to just keep adding to this if you're like, I want to add like A custom Id like 123. You wouldn't do this, you would actually instead just pass a single object that's like this is the character and this is the id.

[00:07:47] So payloads are typically done in a single argument. Try not just spread them out beyond that. And like I said, if you need more nesting, then by all means use an entre. All right, but we don't need to do that. So let's go ahead and actually just emit the character directly.

[00:08:00] And then with that payload, we can actually just push that over. So let's go ahead and verify that this works. Refresh, boom, and he's Zuko Aang bam. And there you have it. And that is a way that you can implement the prompts in a way that lets you render exactly what you need.

[00:08:18] But then when you when it's time to actually do something the child can tell the parent that hey it's there's this thing that I'm requesting please do what you will with it. Does anyone have any questions regarding what the solution that we just went to, over.
>> If you wanted to have your favorite be a separate favorite module, and so, you want to call that function in another module in Shell module.

[00:08:45]
>> Okay.
>> From the template code or something.
>> So let me make sure I understand the question correctly. So let's say in the event you're mentioning that the favorite Functionality is something that's shared amongst different UI components. How would we share that amongst the different components?
>> Yeah, or I mean specifically you have a button with an at-click that says favoriteCharacter.

[00:09:05]
>> Yep.
>> And let's say that function is actually in a different module.
>> Okay, so with this button, you're saying that this is in a different module. So, okay, so you're saying that in this example you'd have, let's say we'd have a utilities folder that has a, favorite.js, for example.

[00:09:31] And so is that what you're kind of referring to, where there's like a function that like will,
>> Okay, I was thinking have a component that displays the favorites and then have the ad favorite function also inside there.
>> I see, okay, got it. So the scope here is you're saying that having the favorite lists scoped with the component directly.

[00:09:53] So actually, it's not this scenario. The idea here actually being that, instead let's go and create that favoriteList characters.view. And so in this case, are you referring to the fact that like we would be rendering out the list here then.
>> Yeah.
>> So got it. So here okay, let's see, so inside of here, we're doing another refactoring here.

[00:10:25] We have our data being the actual favoriteList that's being tracked here. And then this is where we're actually rendering the favoriteList, which is gonna be this block right here. And apparently we have SFC condition, so that is that whole thing. And then drop that in here. Okay, so that should be good.

[00:10:47] FavoriteList is good. That's good, okay. Now the question here is we need to import favorite characters. So let's do that real quick favorite characters and drop that as well. And then once we have that you said that you want to render it here. FavoriteCharacters like this, okay.
>> And I guess you told me where you'd put a function to addFavorites but for the variables inside that module.

[00:11:18]
>> Right.
>> So how would you go about.
>> Okay, and then variables in here. And I think something's missing those something must be delta resolve component because I think I misspelled it. What do you say?
>> Which favoriteCharacters
>> See the one [LAUGH] that gets me this is why I generally do list anyhow.

[00:11:43] Okay, no favoriteCharacters yet, okay. So are you saying that in this particular context you're saying, we clearly have the favorite functionality inside of the card here? And you're saying that what if we had like another section that also had like a favorite button to add characters?
>> Guess am just says,

[00:12:02]
>> Yep.
>> How would you the data over into the favorite list variable inside the favorite characters component.
>> Yeah, this is where it gets tricky. So at least with the tools that we have now, you would basically have to do. Okay, so if you've admitted this, you would admit this.

[00:12:25] I'm not sure if it actually makes sense because so the thing about we have to remember when it comes to emit some props is that it's a top down relationship. And the problem we're trying to solve here is a sibling relationship because character card contains data that bender statistics are not binary statistics.

[00:12:42] Favorite characters and character card are trying to talk to each other basically, at this point. And so usually what happens at that point is where you want some sort of alternative state management solution. Where you have like, basically, as a preview is you'd have stores and we probably would have like a favorite store.

[00:13:00] And the favorite store becomes a file that becomes basically a JavaScript module that's shared between the two components that care about that. And that way, the updating becomes cleaner. And in fact, what's interesting though, is that once you start doing these stores, sometimes the omit goes away actually because now you're actually not thinking about admitting to a parent, you're just updating the store.

[00:13:18] And so that can do a lot in terms of like cleaning up code and that kind of stuff. But I wanted to at least start with the fundamentals of like if you're dealing with two components parent child this is like kind of like best practice for how we approach things.

[00:13:30] But then what tomorrow once we talked about store module and that kind of stuff is gonna be all sorts of fun so.
>> The situation you have here this is where that generic list component could be useful.
>> Yep.
>> Where you're passing as a prop the list of characters into one list, the list of favorites into the others, and then using functions to update those separate lists.

[00:13:49]
>> Exactly, yep. Great.