Vue3 Composition API + TypeScript 環境でTSX(JSX)を使ってみよう!

今回はVue3のComposition API + TypeScript環境でTSX(JSX)を使う方法を紹介したいと思います。Composition APIって何という方はよろしければこちらもご覧ください。

環境

本稿ではVue CLIで作成したTypeScriptベースのアプリを前提にしています。

Vue3.2.19
Vue CLI4.5.0
TypeScript4.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の表記方法には劣る部分がありますが、今後を楽しみにしたいと思います。

最後までお読みいただき、ありがとうございました。

コメント

タイトルとURLをコピーしました