Vue 3 Setup Ref

Posted on  by admin

本指南假定你已经阅读了组合式 API 简介和响应性原理。如果你不熟悉组合式 API,请先阅读这两篇文章。. 使用 setup 函数时,它将接收两个参数:. setup 函数中的第一个参数是 props。正如在一个标准组件中所期望的那样,setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新。. 但是,因为 props 是响应式的,你不能使用 ES6 解构,它会消除 prop 的响应性。.

  • 如果需要解构 prop,可以在 setup 函数中使用 toRefs 函数来完成此操作:. 如果 title 是可选的 prop,则传入的 props 中可能没有 title 。在这种情况下,toRefs 将不会为 title 创建一个 ref 。你需要使用 toRef 替代它:.
  • 传递给 setup 函数的第二个参数是 context。context 是一个普通 JavaScript 对象,暴露了其它可能在 setup 中有用的值:.
  • context 是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context 使用 ES6 解构。. attrs 和 slots 是有状态的对象,它们总是会随组件本身的更新而更新。这意味着你应该避免对它们进行解构,并始终以 attrs.x 或 slots.x 的方式引用 property。请注意,与 props 不同,attrs 和 slots 的 property 是非响应式的。如果你打算根据 attrs 或 slots 的更改应用副作用,那么应该在 onBeforeUpdate 生命周期钩子中执行此操作。.

我们将在稍后解释 expose 所扮演的角色。. 执行 setup 时,你只能访问以下 property:. 如果 setup 返回一个对象,那么该对象的 property 以及传递给 setup 的 props 参数中的 property 就都可以在模板中访问到:. 注意,从 setup 返回的 refs 在模板中访问时是被自动浅解包的,因此不应在模板中使用 .value。.


setup 还可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态:.

  • 返回一个渲染函数将阻止我们返回任何其它的东西。从内部来说这不应该成为一个问题,但当我们想要将这个组件的方法通过模板 ref 暴露给父组件时就不一样了。.

Will You Use TypeScript in Vue?

我们可以通过调用 expose 来解决这个问题,给它传递一个对象,其中定义的 property 将可以被外部组件实例访问:.

  • 这个 increment 方法现在将可以通过父组件的模板 ref 访问。.
  • 在 setup() 内部,this 不是该活跃实例的引用,因为 setup() 是在解析其它组件选项之前被调用的,所以 setup() 内部的 this 的行为与其它选项中的 this 完全不同。这使得 setup() 在和其它选项式 API 一起使用时可能会导致混淆。.
  • I am sure you have already seen that defineComponent is the key word for TypeScript in Vue 3—but do you know how it works?
  • Let’s take a peek behind the curtain and see where the magic happens!
  • Imagine the situation: It is the end of a long coding day and all your logic is working perfectly—like a brand-new Ferrari with a V12 engine and only 4 miles on it.
  • But, there’s still that one nasty TypeScript error that doesn’t want to go away, and it’s breaking the build no matter what you try!
  • I’ve been there, and if you’ve felt this way too, please accept this hug from me.

# コンポーネントプロパティへのアクセス

TypeScript support in Vue 2 was not good enough to use—there were many missing cases and many hacky workarounds. In Vue 3, on the other hand, we have the amazing defineComponent method that makes it very easy to move existing projects to TypeScript—so easy that even your cat could do it for you.

  • Whether or not you like TypeScript, I’m going to try to convince you that it is one of the greatest new features in Vue 3.
  • Its superpower is to save you time by catching errors and providing fixes before you run code.

This actually means that you test while coding. It also makes it possible to instantly use lots of tools that can increase productivity, like VueDX, Vetur or the amazing Volar for example. Once you set it up, you will be able to use all kind of autocompletions of modules, global components configurations and quick type fixes, and all this will be achieved without the need to even build our project.

I will try to reveal all the information I found about TypeScript in Vue 3 in the lines below—so you can feel much more familiar with it and can think of it as an option when starting a new Vue CLI project.

# Render 関数での使用

If you peek at the official Vue 3 documentation, you will notice that there plenty of examples that explain how to use TypeScript in many different scenarios.

The coolest part is that in order to have all this working, you don’t have to remember to include different kinds of interfaces for the component.

All you have to do is wrap the object of the component setting in a defineComponent function.

Having this option provides the ability to instantly embrace TypeScript in even larger codebase projects.

# 使用 this

This is exactly the approach that keeps proving that Vue is the easiest JavaScript framework to get started with, isn’t it? If we had to add the types without the defineComponent function, we would need to add a complicated combination of interfaces before each of our components depending on its content, as it is done in the imaginary example in the code below:.

That was not pretty code for everyday usage, was it? That exactly is one of the reasons why the anti-TypeScript community exists.

Not only that, but we would always have to choose a different interface declaration for each component based on the following five significant Vue declaration cases.

A setup function. An object format with no props. An object format with array of props. An object format with object props.

A custom option definition. That would be a horrible experience, wouldn’t it!? And that is exactly why defineComponent is here! The concepts behind defineComponent bring us back to the roots of JavaScript—the pure functions and TypeScript function overloading. To make it easy for users, all the logic is hidden behind one name: defineComponent.

We always pass any object and return the correctly typed object.

All the cases for different objects that could create a Vue component are handled in separate overloads.

The exact code for its implementation could be found in the GitHub repository here, but I’ll try to explain each overload below:.

# テンプレートでの使用

If you are not familiar with function overloads, think of them as many functions with the same name, just different parameters (by number or type) that still have the same return type.

The first overload is dealing with the case when we create the component from a setup function:. The second one is the case when the props are defined as an empty object:. The third one is the case when the props of the component are defined as array of strings and defineComponent is expecting props as an interface of a collection—Readonly<{ [key in PropNames]?: any }>.

What Is The Main Idea Behind It?

Here is how it should look:. The fourth one is the case when the props are defined as an array of strings and the function is expecting props of type PropsOptions extends Readonly, as shown below:.

How Is It Implemented?

The “last but not the least” option is to pass an object or type unknown or an object with defined setup and name:.

As you see, all these cases are responsible for different scenarios, yet the return type is always the same: a defineComponent interface with all the types you need to apply for the props, data and the other settings that are needed for the component.

Yet another piece of evidence that the best solutions are usually the simplest ones. Using defineComponent is extremely helpful and allows you to grab your project and join the dark forces of TypeScript world—yet if you want to have correct types on all the properties that could be used in the component, you may need to add a bit more love.

# 使用渲染函数

Below is the cheat sheet piece of code that I personally use to peek from time to time at how to add types correctly in a Vue component:.

My favorite part about using defineComponent and TypeScript in Vue 3 is adding tests to the project. It is a true game changer in that area and even makes the process delightful because it provides those awesome autocompletions that help cover all the use cases when writing tests.

Even better, TypeScript also reduces the overall number of tests that are needed because the types are checking most of the possible configurations statically.

  • Here is an example how a simple test-writing process would look like when we want to test a simple Vue 3 component with a Kendo Native Grid in it.
  • And here is the code:. You can check other similar examples with all the Kendo UI for Vue components in our repository here. My next blog will cover state management techniques when editing Grid items, so stay tuned for that. Now that you have read all this, you can decide if using TypeScript in your current Vue project is right for you.
  • Personally, I already know I’m going for it! Thanks for reading so far! For more Vue tips or Kendo UI for Vue news, follow me on Twitter at @pa4oZdravkov.

Happy TypeScript and Vue coding! このガイドは Composition API の導入 と リアクティブの基礎 を既に読んでいることを想定しています。Composition API に初めて触れる方は、まずそちらを読んでみてください。.

setup 関数を使う時、2 つの引数を取ります:. setup 関数の第 1 引数は props 引数です。標準コンポーネントで期待するように、setup 関数内の props はリアクティブで、新しい props が渡されたら更新されます。.

しかし、props はリアクティブなので、ES6 の分割代入を使うことができません。 props のリアクティブを削除してしまうからです。. もし、props を分割代入する必要がある場合は、setup 関数内で toRefs を使うことによって分割代入を行うことができます:.

What Would We Do Without 'defineComponent'?

title が省略可能なプロパティである場合、 props から抜けている可能性があります。その場合、 toRefs では title の ref はつくられません。代わりに toRef を使う必要があります:.

setup 関数に渡される第 2 引数は context です。context は一般的な JavaScript オブジェクトで、setup の中で便利と思われる他の値を公開します:. context オブジェクトは一般的な JavaScript オブジェクトです。すなわち、リアクティブではありません。これは context で ES6 分割代入を安全に使用できることを意味します。.

attrs と slots はステートフルなオブジェクトです。コンポーネント自身が更新されたとき、常に更新されます。つまり、分割代入の使用を避け、attrs.x や slots.x のようにプロパティを常に参照する必要があります。また、props とは異なり、attrs と slots のプロパティは リアクティブではない ということに注意してください。もし、attrs か slots の変更による副作用を適用したいのなら、onBeforeUpdate ライフサイクルフックの中で行うべきです。.

Vue2 Options-based APIVue Composition API
beforeCreatesetup()
createdsetup()
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted
errorCapturedonErrorCaptured

Writing Tests With Typescript like a Pro

expose の役割については後で説明します。. setup が実行されるとき、以下のプロパティにのみアクセスできるようになります:. 言い換えると、以下のコンポーネントオプションには アクセスできません:. refs (template refs). setup がオブジェクトを返す場合、コンポーネントのテンプレート内でオブジェクトのプロパティにアクセスすることができ、 setup に渡された props のプロパティも同じようにアクセスできます:.

setup から返された refs は、テンプレート内でアクセスされたときに自動的に浅いアンラップされるので、テンプレート内で .value を使用すべきではないことに注意してください。. setup は同じスコープで宣言されたリアクティブなステートを直接利用することができる Render 関数を返すこともできます:.

Render 関数を返すことで、他のものを返すことができなくなります。内部的には問題ありませんが、このコンポーネントのメソッドをテンプレート参照から親コンポーネントに公開したい場合には、問題となります。.

この問題を解決するには、expose を呼び出して、外部コンポーネントのインスタンスで利用可能なプロパティを定義したオブジェクトを渡します:. この increment メソッドは、親コンポーネントでテンプレート参照を介して利用可能になります。.

setup() 内では、this は現在のアクティブなインスタンスへの参照にはなりません。setup() は他のコンポーネントオプションが解決される前に呼び出されるので、setup() 内の this は他のオプション内の this とは全く異なる振る舞いをします。 これは、setup() を他の Options API と一緒に使った場合に混乱を引き起こす可能性があります。.

# 参数

Maybe you feel comfortable when using the old Vue options-based API, or maybe you don’t like to think of everything as functions but properties/methods with OOP mindset. The creators are developing Vue, make it better year after year and give us more options. Just try it and feel the good.

Happy learning! See you again!

# 访问组件的 property

You can find the complete source code for this ‘Vue Composition Api example’ on Github.

# 结合模板使用

– Vue 3 CRUD example with Axios & Vue Router
– Vue 3 Authentication with JWT, Vuex, Axios and Vue Router