Production-Grade Vue.js

Composition Modules

Ben Hong

Ben Hong

Production-Grade Vue.js

Check out a free preview of the full Production-Grade Vue.js course

The "Composition Modules" Lesson is part of the full, Production-Grade Vue.js course featured in this preview video. Here's what you'd learn in this lesson:

Ben demonstrates how the Composition API allows code to be abstracted into separate, reusable modules. Methods from these modules can be individually imported into a component.


Transcript from the "Composition Modules" Lesson

>> I'm gonna go ahead and clean this up a little bit, just so that we have a lot of random increment counts with the numbers so I'm gonna go ahead and clean this up. So again, if we were to convert this fully over from options API to our basically Into competition API will reface define, never used benefit of UCLI letting me know what's not used, great.

So here we can clean this up, okay, so this should be this one work and increment and we're good, okay? So the question here is now if we actually want to share let's say current count with multiple components. So in this case, I think the easiest thing for us to do let me full screen this, is to go ahead and show this by creating, let's call it a second hello world, hello world view.

So let's go ahead and duplicate this file and in case you're wondering where that is in Vuex code, this is actually an extension. It does not work by default I learned recently, so here let me just go ahead and show it marked very clearly, that this is current count number two, basically, okay.

So, when we render this on to the page, I just need to copy this and import these two together, well 2, yay, autocomplete. So we can see here now that we have two components using the same functionality and the same shared state. And again, typically you might consider using something like mixing or providing jack that app like shoots into it but we're gonna go ahead and see how the composition EPI manages this.

And so I'm gonna go ahead and fullscreen in this case just because we need to actually kinda see what's happening. So the way we're going to start with this is we're going to go ahead and create a folder that will contain sort of all of the functionality that we want in order to track basically the things we're going to use inside of our component.

And a lot of you who, for any of you who've done some reading, composables is a fairly popular folder name that is basically becoming quite commonly used inside to refer to basically the idea is these are composition API functions. While this is still being tested out, like so far in my own experiments and in my own projects, I found that composables has a couple of downsides to it.

One, it's a word that's very specific to the view stack and so if someone who doesn't really know about composition API looks at it, they're gonna be like, what the heck are composables? Now again, we're all like we're all immersed in this, so it kind of sort of makes sense for us to call it this.

But when we're talking about enterprise level apps, it's actually really important for us to think about how easy it is for people to understand things. And so to me, this is actually one of the things that makes view like particularly why I'm such a big fan of it is because the fact that even like a designer with just some basic level HTML can walk into a component and get a general sense that like, this is current text.

This is rendering the data, this is increment count, they don't need to know that this is the view method that takes like like JavaScript, like it has a discount. It doesn't need to know they don't need to know that but composable is comes with unfortunately, that level of like, what do I need to know to understand this?

And the truth is, is that most of the times when we're putting inside of this composable functions It's just JavaScript like. And so similarly, when you have a utility function, or sorry, utility folder, you wouldn't call it like these are lodash doubles, because we're importing lodash like, these are utility functions.

And so again, take this with a grain of salt, this is just my opinion. I prefer the term like the folder name features, because these are going to be containing the things that were features that will enhance our components. And so in this particular case, right, we want to share the count and so another convention that you'll see use is the use functionality, so in this case, I'll call it useCounter.js.

And so useCounter.js is again, just the JavaScript function, sorry, just the JavaScript file and so what I'm gonna do is I'm just gonna copy all of this here and just cut it out and drop it into useCounter. So let me go ahead and hide the sidebar, let me go ahead and jump over here.

All right, so now when I save hello world, this should just, everything should just break immediately, which makes sense, right? Because, now, it doesn't have anything at all. But here we see that use counter now is a JavaScript file, but we wanna actually be able to create a module, right?

It's a model that we wanna be able to import, what does that mean? We actually then need to actually export it, so this is where we might go export, in this case, I'm going to call a constant called use counter and it's going to be a basically a function continuous counter like this.

Just gonna call it like that, I think that's gonna or do I have to? Wait no, I yeah has to be like this, There we go. So here we go we have the arrow function, so this is a function that's gonna return us something, right? [COUGH] And so in this case when use counter is executed, we wanted to return this object to us.

Now, similarly to our hello world view, right because it is an actual JavaScript file, it doesn't inherently know these helper methods, we need to go ahead and re import those onto our individual file here. And so now that we have this, everything should be hooked up correctly. And so the question is now how do we call used counter inside of helloworld view app?

And the way we do that is that we have o call it inside a setup, this is the point where, as the name indicates, we're setting up our component and so what we do is we start by importing our basically our feature. Let me go back, so features use counter and then so I so we exported use counter here, so this maps directly.

Okay, so this is where split screen would help, so let me do that, oops, not this one. There we go, okay, so here, this use, I'll call it use counter, I'll just call us kind of method just because I want it to be very explicit so here the method is mapped to here.

And the file name is called use counter so just to sort of allow you to map that better. Okay, so now how do we call it? Well, we say, so basically say, so we have the object so countState, I'll call it countState is going to or account. Yeah, call countState now, and then we're going to say use counter method and we're going to call it directly.

And so let me save that real quick and then switch it back over to two thirds and then once we've used that I can return it out into our object. And let me just show this on the page so y'all can see what count state looks like. It's already been distracted, I totally forgot okay, so here if everything's working correctly, you can see that something is actually updating.

And so wait, no, it's not updating, I have the wrong HelloWorld, hang on, let me check with it, doo doo doo instance update is not function. Reload, there we go I was gonna say, okay, so something is missing so let me drop this real quick. And so let's expose what current count is and so here, it's not exposing anything that's fine, a countState sort of wants to say, here we go, okay.

So we'll see that current count is an object that has basically like we see the current count here and then that's about it. We don't see anything else, so let's log that just to make it a little bit clear. And so we have the object here, yeah yeah, I was gonna say, I was like, where did that go?

And then we have our increment count and this makes sense because we've gone ahead and exposed it as the different pieces and so you might be wondering like, why is it breaking? Well, because we're turning the object directly, so it's an object of an object. And so what a lot of people do actually in this case is they'll, destructure this immediately into current count and increment count because they know that's, what's being exposed.

And so then they would return this here, like this and then current count, that's gone, refresh. Okay, there we go, count status access to ref count, I forgot I'm referring to it here again so here uncomment save, okay, it works, okay. Dangerous of like kidding, but that's okay, so what you see now here is that current count rate is being let me split screen one more time for everyone.

Current count is being pulled from here because state has been destructuring and so we're getting this piece inside of here that we can pull out and then we can pull out increment count from this method over here. And so if we think about this back to our discussion regarding mix-ins and provide inject, this is really, really cool because now you have a really explicit path of inheritance.

Not only are you could suddenly be naming wise, you can try to make sure everything is named correctly. But you can see here that use Turner method comes from this method, which comes from this file and that is huge when it comes to things that scale. Because I don't know about you but I've certainly worked on a lot of projects where you have contractors working on other sides of the world.

And the more we can be explicit about how things work the he's the less documentation and communication it needs. Because you have basically made it like painfully obvious like where everything is coming from and it go to way sorry painfully sounds negative but is this crystal clear in terms of where he's coming from?

And this is why composition API is like in like mounds superior over these provide inject and mixins methods. Because now you might be thinking, okay, can we just do the same thing inside of hello world too for example so you we absolutely can do that. So in HelloWorld2 for example, this is really cool because we can say, okay, in this case, we want to go ahead.

We don't actually care about the increment count we actually want it to be positive equals 2 in this case, right? HelloWorld2 want to increment by 2 but we still want that current count like that's being managed inside of it. That's fine, so what we would do then in this case is we would go import similar to before, right?

We pull out our feature, our features are used on our feature and we're gonna say that the current count use counter method, that's what I called it. And then we're gonna only pull out the current count, because that's all we care about. Again, so this, in this regard, this is similar to provide inject because you're choosing the component gets to choose what exactly they care about.

And so in this case, I can, do this and then I can ignore this exposed current count but this is gonna break. There is a reason for this, and that's why I did it this way, two rest is gone, reactive is going to actually, all of the helper methods are gone, okay.

So you might be thinking like, wait why doesn't this work? We had current town before and so for example, let me just comment this out, let me just comment this out real quick and so there we go, okay. And so the reason this is is that, remember what we did inside of us count look, I don't want to print that command p in the wrong window, we just structured everything into refs.

And so again, this is where unfortunately there is a little bit that learning curve does exist when it comes to the composition API. And it's that everything is a ref now, it's actually not reactive so you can't just refer to it directly. And so what we need to do then if we want to mutate it It's just a current count.value.

And so now when we go ahead and refresh, you'll see now that in the first one, this increments by one, but in this one, this increments by two. And so now you have these, think of them a little bit they they're basically a little bit factories at this point, right?

Because in this case use counter method is a function that generates this thing. Now, what if instead we just made it anyway so, this is the general idea behind sharing like sort of extracting out your functionality into the composition API pieces. So as we can see, the composition API is pretty great as far as letting us pull out what we want and then just expose it to the component directly.

The key thing here though, as you notice, though, is that when it comes to now architecting how your code is organized, it is now completely reliant on you. This is probably the composition API's in a sense because downside, because it's a double edged sword. Without the sort of the guard rails that View typically provides with the options API.

This means that if you end up in an empty pattern, if you end up doing something that ends up making it difficult to refactor, those are things that are now up to you and it's up to you to practice those good software architecture principles. In addition, as far as the other concept is, as we saw, unless you understand what refs are and you kind of have a sense of the V activity engine, what proxies are, why things are happening, competition API does have that learning barrier.

And so if you're onboarding new developers, you might be thinking like this, this can be a bit, there's a little bit of a learning curve, let's put it that way. And so going forward, one of the questions commonly asked is like, does this mean I should like go and rewrite everything with the composition API?

Absolutely not, all the techniques including this one, as great as the composition API is We use them to solve specific problems and achieve specific impacts. I know that as developers we really enjoy like playing with the new shiny thing and if you wanna do that, I totally recommend you doing that, just do that on like a side project rather than on production.

It's not worth like, going in and just reconfiguring everything just because the composition API is fun to use or like clean to use. Like anything else, progressive enhancement and migration is key to long term success and terms of production grade applications. And so similarly, like, if you think the composition API can solve a problem for you, then yes spend the time to refactor it and do that but otherwise your options API code is completely valid.

And not only that, like going forward, like what'd, you can do is like, if in the future is certain that certain things could use a composition API. Then you can build those new features, but whatever you might see or read on the internet, both the options API and the composition API are valid approaches.

And you just need to know the pros and cons of using each and then use them accordingly because as we mentioned with the competition API, you get the con of that learning curve of like how everything works. And more importantly, people need to be a lot more familiar with JavaScript, right?

Like all this de-structuring and like factory functions, like this is very JavaScript oriented. Whereas like the options API has the beauty of like having structure and like people grasp those things, once they do these conventions, it just works. I think the best example I've personally encountered with this was teaching a designer who hadn't coded for like five years and thought that when she took the introductory workshop that she wouldn't be able to like, catch up with everyone.

But within the hour, she had the options API up and running and was building things and making things work. I think we have to remember that is the beauty and power of the object API is that that allows people from all walks of life to really come in and start contributing.

Whereas this composition API does have a bit more of that learning barrier. So keep that in mind as you're choosing what's best for your team, and how to best basically like represent your codebase in a way that like is still accessible for everyone, and yet still scalable.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now