今回はVue3のComposition API + TypeScript環境でTSX(JSX)を使う方法を紹介したいと思います。Composition APIって何という方はよろしければこちらもご覧ください。
環境
本稿ではVue CLIで作成したTypeScriptベースのアプリを前提にしています。
Vue | 3.2.19 |
Vue CLI | 4.5.0 |
TypeScript | 4.1.5 |
TSXの導入
それではTSXの導入を始めましょう!
VueではTSXを利用する場合、以下の2つの記述方法があります。
- .tsxファイル
- .vueファイルのscriptタグにlang=”tsx”を指定する
どちらの方法でもTSXは記述可能ですが、.vueファイル内に記述する場合、styleタグを併用可能で、cssのスコープ化が使えるというメリットがあります。
本稿では.vueファイル内に記述する方法で説明を進めていきます。
基本的な使い方
以下のサンプルを元に実装内容を確認していきましょう。
<script lang="tsx"> // (1)
import {defineComponent, ref} from "vue"
export default defineComponent({
name: "Hello",
setup() {
return () => (
<>
<div>Hello</div>
<div>World!</div>
</>
)
},
})
</script>
まずscriptタグのlang属性にtsxを指定します(1)。この設定を行うことでscriptタグ内がTSXとして扱われます。
基本的な記述方法は通常のComposition APIでの実装方法と変わりませんが、TSXを利用する場合はsetup関数の戻り値にTSXを返す関数を返すようにします。
変数の出力
Vueのtemplateでは変数や式を使用する場合に{{ }}形式で記述していましたが、TSX(JSX)では{}形式で記述します。
refを使用する場合は、templateの場合とは異なり、.valueを付ける必要があります。
class State {
age = 0
job = ""
}
setup() {
const name = ref("JOHN")
const state = reactive(new State())
return () => (
<>
<div>Hello {name.value}!</div>{/* refは.valueでアクセス */}
<div>AGE: {state.age}</div>
<div>JOB: {state.job}</div>
</>
)
},
class, style
Reactではclass属性はJavaScriptの予約語と衝突するため、classの代わりにclassNameを使用しますが、VueのTSX(JSX)ではclass属性をそのまま使用することが可能です。
const retire = ref(false)
return () => (
<>
<div class={retire: retire.value}>HOGEHOGE</div>
<div style={fontSize: "20px"}>FUGAFUGA</div>
<div class="fuga">FUGAFUGA</div>{/* 通常のclass属性の指定も可能 */}
</>
)
</script>
<style>
.retire {
color: red;
}
</style>
templateではclass属性と:class属性を合成する機能があり便利なのですが、TSX(JSX)ではこの機能を利用できませんので、注意してください。
v-if, v-show
v-showはtemplateの場合と同じように真偽式を指定することで利用できます。
const show = ref(true)
return () => (
<div v-show={show.value}>SHOW!</div>
)
v-ifはTSXでは使用できませんので、Reactと同様に式で実装する必要があります。
const active = ref(true)
return () => (
<>{active.value && <div>ACTIVE!</div>}</>
)
v-model
VueのTSXではv-modelが利用可能です。
const name = ref("")
return () => (
<input v-model={name.value} />
)
.lazyや.number, .trimなどの修飾子を指定する場合は、次のようにします。
<input v-model={[name.value, ["lazy"]]} />
<input v-model={[age.value, ["number"]]} type="number" />
また、コンポーネントのパラメータにv-modelを指定する場合は次のようにします。
<Some v-model={[name.value, "name"]} />{/* Someコンポーネントのnameプロパティにv-modelを指定する場合 */}
Slotの利用
TSXで子要素をラップする場合、childrenを使用しますが、VueのTSXではslots属性を使用します。
Slotの定義
return () => (
<>
<h1>{slots.default && slots.default()}</h1>
</>
)
Slotを使用する
return () => (
<Some>
<div>HELLO!</div>
</Some>
)
デフォルト以外のslotを利用する場合は、次のようにします。
const slots = {
addtional: () => <>addtionalスロットのメッセージ</>
}
return () => (
<Some v-slots={slots}>
<div>HELLO!</div>
</Some>
)
まとめ
今回試してみて感じたのですが、本構成は従来までのVue開発に比べ、React並みに型が利用でき、Vueの開発における一つの最適解ではないかと勝手に思っています。まだまだIDEのサポートが甘いところがあり、従来までのtemplateの表記方法には劣る部分がありますが、今後を楽しみにしたいと思います。
最後までお読みいただき、ありがとうございました。
コメント