- Today, we'll be talking about some really cool features from Vue 3. Vue 3 offers us so many new things. The most famous feature
in Vue 3 is probably the conversation API. It allows us to write our
components at different syntax while offering what code usability. However, there are a
few other new synthetic format that we can use to
create our components in Vue 3. These lesser known patterns
are a bit different from the standard composition API and classic options API. In this video, we'll be
exploring three of them. These are the three syntactic
patterns we'll go over. We'll go through the
pros and cons of each. I've also rated each of them
against a set of criteria. Don't worry, I'll explain
each one of these ratings and my reasons for them. If you want to follow along with the code, make sure that your app is running Vue 3. You can create a brand
new Vue 3 app using Vite. We'll also be doing some TypeScript stuff. So you will need a TypeScript
app to follow along. All you have to do is to change the template year with view, dash, T S. Now that we're ready, let's jump right in to our first pattern. Hybrid means to mix two
different types of APIs together, the options API and decomposition API. You can keep most of your
code in the options API and still benefit from the co-sharing features of the composition API. Let's apply this hybrid
pattern in a component. We're starting with the brand new app. Here I'm going to paste in some code. It's a component written completely in the classic options API. It shows a count and
we add one to the count every second automatically via the timer. There's also a button
for resetting the count. It will trigger the reset function, which is defined down here. Now let's assume that this
automatic candling logic is needed across multiple components, not just this one component. And that's exactly the
kind of problem that the composition API is meant to solve. Let's see how we can tackle this. First, we can extract the
automatic canning logic to conversation function
called useAutoCount. Copy this and put it here. Make it assigned with the ref. Next, we also want to
move this lifecycle hook to decomposition function. We'll create a same lifecycle hook, but it's called onMounted
instead of mounted. Let's show that it's important up here. My IDE has done that for me automatically. And we can move the
code from here to here. Now we can remove this and let's go ahead and
remove this as well. Since we're using ref, we
have to import it up here. There are still a couple
of things we have to do. Change this to count dot value and we have to return count. Now our component is
missing the core logic. So it's not even working at this point. What we have to do is to
first create a setup function, and we can call the use
auto count function in here. And this will set up the
automatic counting logic for us. Lastly, return to count so that
the template can access it. The count goes up automatically
and we can reset it as well. Now to improve this, we
can add the parameter to this composition function, and we'll use this
parameter as the initial value for the count. So now we can decide which number to start with right inside
the component itself. Now our component is using
both decomposition API and the options API. And we also have the freedom to store this composition function
in a separate file. Let's do that now. First create a folder and the file for this function with the same name and go back to where we were, copy the function including
the impost statement, put it in a new file, and
make it the default export. We're done here. We just need to go back
to your out component, and import the new composition function. And we're done. Not only that our
component file is cleaner, we can reuse decomposition
function in another component the same way we did here. This hyper syntax is a perfect
way to use the composition API in your existing code
without a major refactoring. Now let's take a look at a
ratings for the hybrid pattern. Versatility refers to quality of being able to do many things. This hybrid syntax has all the
powers of decomposition API. You can think of it as a special version of the composition API
where the life cycle methods and even handlers can
be defined in options instead of the setup function. Compactness means that
the components part can be brought together in a coherent fashion. Since we're mixing two types
of syntactic structures our code doesn't look coherent. For example, inside the setup function, we're referencing the counts
date as simply just count. But in the reset method
we're using this tag count. Type script friendliness is about ease of using TypeScript under a
particular components syntax. This is not the same
as TypeScript support. UGS has TypeScript support for both the options API and the composition API. However, under either one of these APIs, it's not that friendly to
work with props in TypeScript. UGS provides dynamic runtime
type checking for props, and that's a built in feature of UJS. This building tight checking clashes with the static compiled time
type checking of TypeScript. Let me show you what I mean. Here we have a TypeScript version of the same app that we've been working on. In order to make TypeScript
compatible with views built in runtime props type checking. We have to resort to syntax like this. This object type is used as a
place holder in views building type checking system
or using this prop type generic type as a workaround to make props compatible with TypeScript. This is not the most friendly TypeScript experience out there. That's why I'm giving
it a two-star rating. So basically the conflict here is that if we want pure TypeScript annotations, we have to give up this props option that we're so familiar with. To get a glimpse of how
to solve this problem let's take a look at a
functional components syntax. Previously in Vue 2 this is how we create a functional component, but this syntax has been deprecated. This functional attribute is
no longer supported in Vue 3. Now let's take a look at
how we do that in Vue 3. Back in our app component. How about we extract this part and make it a functional component. First create a new file. In Vue 3 a functional component
has to be a pure function. As you can see, we're not
getting any syntax highlight. That's because our file
has the dot you extension. What we need is to pure that JS extension. Let's change this to an assignment. This is more conventional. To define the props in
this functional syntax we have to use the props
property of the function itself. Just like the options API, we can also define the
prop with it's type. And make it required. At this point, you might be wondering, how are we going to use template with this functional syntax? We cannot use template here. We have to use the itch function instead, this is an alternative to template. We use this to describe the
Dom structure of the component. It's going to be a P element
for the class attribute. And finally, he will contain the camp that we passed through to props. And we have to make the props available as a parameter of the function. Let's do an overview of this function. It takes three arguments
to create an element. The first one is name of
the element as a string. This can also be a component. The second one is an object of
attributes. This is optional. The last one is the child element or children as an array of child elements. The equivalent of this in templates syntax will be something like this. So we're able to create elements inside the functional component. You might be wondering
what else is allowed. We can use ref. We can also use reactive,
but there is a catch. We'll talk about this in
a bit lifecycle hooks are not allowed inside the
functional component. Again, I'll talk about this in a bit. It will all make sense. However, we can still create
callback functions here. Let's set it to the click
event at the P element. We can do this with
the on click attribute. And since the function has the same name, EA6 allows us to have
on click here just once. So we don't have to do
on click colon on click. As it stands is functional
component looks a lot like a simplified version of the composition API. Next, let's go back to the app component and import our new functional component. Register it with the components option. And now we can go to the template
and we place this without new component and passing in a prop. We can check it out in the browser. We can confirm that we're
indeed rendering our new functional component because
of the class that we added. Now let's switch to TypeScript. We're still defining
the props the same way that we did in the hybrid syntax. With dysfunctional
syntax we can also define the props in pure TypeScript annotation. We're going to do that in the parameter. Now we don't need this. Since this type annotation
is just TypeScript we can extract this and create custom interface for the props. And use the interface here. Now let's take a look at the ratings for these functional syntax. You might be surprised
by this one-star rating, but this is justified
by two deal breakers. First functional component
has to be stateless. That means he cannot have state. Remember that I said you
can use ref and reactive, but there is a catch. The catch is that when you change a state of any one of
these reactive variables, the component is not
going to get re rendered. Let's do an experiment. Change the value of the ref
in the on click callback and lock the result. Let's create an additional
element to rendered X value. And put the on click event here instead. Now go to a browser, even see
the X value is rendered here. Lets also open the console. When we click on this X element, you see it's updated value
getting locked to the console, but the element itself did not get re rendered with the updated value. It doesn't matter how many
times you click on it. It just stays the same. The second problem is the
complexity of this render syntax. It might look acceptable in our code here. But if you want to do
something more elaborate such as rendering with the loop, it can get tedious to write. It also kind of defeats the
purpose of using Vue JS. So one star for versatility. And you should only use
this functional syntax for components that are stateless and simple. Next three stars for compactness because there's nothing more compact than having everything all inside one function. Lastly, TypeScript
friendliness is still two-star. Let me explain. Even though we're able
to use pure TypeScript annotation in this syntax, there is a drawback that comes with it. There is no building support for defining default prop values. We can still do it with
some Home brew trait, but it's just not very friendly. First, make the cam prop optional, then rename the props
parameter to something else. As soon as it got renamed,
we'll see this error. We just have to create
another variable called props. In here we will set the cam
prop value conditionally. If it's not defined, we set it to the prop that got passed in. If it is undefined, we set
it to the default value. As you can see, we need
all this additional code just to set a default value for prep. It's not very friendly. I think it's a good time to do a recap before we move any further. On one hand, we have this hybrid syntax that offers great versatility, but it's not compact. On the other hand, we
have the functional syntax as is probably the most
compact format ever, but it's not versatile. It only works for components
that is stateless, and you can not use template with it. And both of them have their own moments of TypeScript unfriendliness. So heres back to the question: is there a component of
syntax that is versatile yet compact and also friendly to you when you're using TypeScript? And the answer is yes. And we'll get to that right now. Script set up is a new feature in Vue 3, it became an official feature in Vue 3.2. It's basically just a simple way to create components with the composition API. For example, let's take
a pure composition API component like this one here and refactored with the
script set up syntax. First extract, a set of function. Notice that all the important code is inside is set up function. The code over here is
really just metadata. We can just get rid of it. All we have here is
basically just one function. The scripts set up syntax
allows us to have the content of dysfunction to be on the top
level of this script tack without the function wrapper. But we have to add the setup
attribute here to let view, know that we want to use
this script set up syntax. The import statement have not changed. And finally, we can remove
the return statement because we're no longer
inside the function. Vue will automatically make all the variables in this scope
available to the template. Notice that using this syntax doesn't affect our code in a template, but as a convention, we're going to place the template below the script. And we're done. Here's a before and after comparison. Basically, we just took
the content of the function and put it directly inside the script tag and got rid of everything else. Next, let's talk about how to define props in this new syntax. We just have to use a new
function called define props. It takes the same old props configuration object as the argument. Now let's turn to TypeScript. Next to the setup
attribute we're still using the Lang attribute the same way. Instead of defining a props like this, we can also do it with the
pure TypeScript annotation. Let's first remove this. We're going to use the
generic angular brackets to define the props
type impure TypeScript. And of course we can extract this and create a custom interface. And use the new interface here. Next let's talk about the second
props problem that we had. How to set default values for our props. First, make it optional
with the question mark. As soon as we did that, we get this error. With the user, not a
function called with default, and we can pass an object
as the second argument. Here, we can define the
default value for our prop. And we're done. Now you're probably curious
about as two functions, we didn't import them, so
where did they come from? These functions are
called compiler macros. They only get executed in compile time. And because of that, they don't need to be imported like other functions. And I should also mention
that the compiler macros can only be used with
the script set up syntax. This script set up feature was implemented using the compilers centric strategy. The code we have here will get compiled into a different looking runtime version. We can confirm this by going
to a browser open the Def twos, select the app component here. As you can see, the runtime code is very different from our original code. We don't even see the two
compelling macros that we used. Finally, let's take a look at a ratings for the script set up syntax. In the script, set up syntax, you can do all the things that you could do with the regular
composition ABI syntax. That's why it has the same three-star versatility as the hybrid syntax. We're able to work with the script tack as if it's the setup function itself. So his script tag is now
practically just a function and we don't even need
the return statement. That's why it has the same three star compactness as a functional syntax. With the help of compelling
macros like defined props and with default to streamline everything. It's not hard to see why
this is the most friendly TypeScript experience
in the Vue ecosystem. The script set up syntax is
now officially recommended syntax for using the
composition API in Vue 3, but the other two patterns can still be useful depending on
your unique use cases. Also, don't forget that you can still use the classic options API. I hope that you've learned something useful that you can apply
on your next project. To continue learning, you can check out my
full course on TypeScript with the script set up
syntax at vuemastery.com. Along with the library about
a premium view courses. Thanks for watching!