Vue3 + TSX のすすめ
初めに
なぜこれをやろうと思ったのか。
これに尽きる。
そのタイミングでLINEさんのこちらのPodcastがTLに流れてきたのでチャレンジしてみた。
本記事ではTodoアプリを題材にVue3におけるTSXの私個人の記述方法や所感などを書いていきます。
公式サイトを見てもReactみたいな書き方ではなく、しっくりこなかったので自分なりに書いてみました。
基本的な書き方は結果のコードを参考にしていただければと。
結果はこちら。
基本的なアーキテクチャについてはこちらの記事を参考に作成しています。いつもお世話になっております。
本題
記述方法
Composition-API
を使い、 setup
で RenderFunction
を返します。
import { defineComponent, ref } from 'vue';
import { TestComponent } from './test.component.tsx'
export default defineComponent({
components: { TestComponent },
setup() {
const test = ref('test');
const changeFuga = () => {
test.value = 'fuga'
};
return () => (
<div>
<TestComponent test={test.value} changeFuga={changeFuga} />
</div>
);
}
})
ここで型の恩恵を最大限受けるために、 emits
は全て props
で代替しました。
また props
で全て代替することで、親コンポーネントから子コンポーネントを呼び出すときに型のチェックが行やすくなりました。
props
のリレーも特に問題なくできるレベルになっていると思います。
import { defineComponent, PropType } from 'vue';
import { Todo, TodoUpdateDto } from '@/models'
interface Props {
todo: Todo | null;
onUpdate: (id: string, todo: TodoUpdateDto) => void;
};
export const TodoEditComponent = defineComponent({
name: 'TodoEditComponent',
props: {
todo: {
type: Object as PropType<Props['todo'],
default: null,
},
onUpdate: {
type: Function as PropType<Props['onUpdate'],
required: true,
},
},
setup(props: Props) {
// propsに型がついているので、型の補完が効く
...
}
});
注意する点としては今まで template
で使用する際に暗黙的に展開されていた
- props
- refのvalue
は都度記述する必要があったけど、型による恩恵があるのでそこまで気になるようなことではなかったです。
引っかかった箇所
SFC
の template
で書いていたものを全てTSXへ移行して行った際にいくつか問題が出てきたので、解決したものと解決していないもの分けて紹介します。
解決したもの
-
vue-router
の<router-view>
と<router-link>
こちらはそれぞれ vue-router
が提供する RouterView
と RouterLink
で代替することができました。
import { RouterLink, RouterView } from 'vue-router';
export default defineComponent({
setup() {
return () => (
<div>
<RouterView />
<RouterLink to={{ path: '/todos', query: { completed: "true" } }} >
<a>TodoList</a>
</RouterLink>
</div>
);
}
})
- クラスとスタイルのバインディング
特定のクラスだけ特定の条件下でアクティブにしたいときなどに使用していましたが、こちらは三項演算子を用いて回避しました。
v-model
リアクティブにレンダリングしたいときにはどうしても必要だったので、 jsx-next
を babel
に組み込むことでそのまま v-model
を使えるようにしました。
解決しなかったもの
style scoped
小さいプロジェクトだとここはあまり気になるポイントではないけれど、選択肢としてないのはつらいですよね。
どうやってstyleの対象範囲を限定できるのか方法が見つからなかったため、断念しました。
あとは特に支障はなく書けました。
まとめ
やはり型による恩恵を最大限受けれるのは大きなメリットと言えました。
また template
では[1]できなかった optional chaining
や nullish coalescing
などが使えるもよかった点でした。
Vue2で Composition-API
を使うための @vue/composition-api
では setup
による render function
はサポートしておらず[2]、上記で述べている vue-router
についてもnextである v4
からのサポートなのであいにくVue2での導入は厳しいと言わざるおえないです。
「Vueを導入しても型がちょっと、、、」と言われがちですが[3]、一定の設計を元に導入を行えば、Vue3では無理なくTypescriptで書くことは可能かと思います。
今後Vue3を検討している人に対して何か参考になれば幸いです。
型はいいぞ。
雑談
Vue3になってからテストの書き方が結構変わっているので、マイグレーションがかなりつらい印象。
createLocalVue
はどこにいったんだ。
storeはいいけど、routerはどうすれば。
一応 createRouter
した router
自体をテストで読み込んでみて、新しく増えた global: plugins
に突っ込むことでスナップショットまでは取れたけど、これでいいのか感が、、、。
詳しい人いたら教えていただけるととても助かります。
あとLINEさん[4]が
Vue test utilsが .tsx の読み込み時に型を補完してくれない
とあったけど、特に問題なく補完できたのでそもそもの書き方が違うのだろうか。今回書いたコードにテストをきちんと全部書いていないので考慮が足りない部分があるかもしれない。
Discussion