Open5

Nuxt3をはじめる②

HIR0HIR0

ルーティング

Nuxtではファイルシステムルータという仕組みを採用しており、pages/ディレクトリ内に格納されたファイルに応じて自動的にルーティング(URLとコンポーネントの対応付け)が生成される。

pages/ディレクトリ内に*.vueファイルを追加すると、自動でそのファイル名やフォルダ階層がURLに対応する。ルートに該当するファイルはindex.vueというファイル名にする決まりがある。

my-nuxt-app
├ pages/
│ ├ index.vue  # GET /で表示
│ ├ about.vue  # GET /aboutで表示
│ └ users/
│  ├ index.vue  # GET /usersで表示
│  └ [id].vue  # GET /users/123で表示...

NuxtPageタグの内容がpages/ディレクトリ内のtemplateタグ内の内容に置き換わるイメージ。

app.vue
<template>
    <div>
        <NuxtPage />
    </div>
</template>
pages/index.vue
<template>
    <h1>Index</h1>
</template>

ページ間の移動

Nuxtのルーティング機能を利用してページリンクを作成するにはNuxtLinkタグを利用する。
スクリプトブロック内で遷移させる際は、userRouter()を利用する。

<template>
    <NuxtLink to="/about">Aboutへ移動</NuxtLink>
</template>
<script setup lang="ts">
const router = useRouter()

function goAbount() {
    router.push('/about')
}
</script>
HIR0HIR0

レイアウト

Nuxtにおけるレイアウトとは、ページ全体に共通する見た目や構造をまとめるための仕組みのことを指す。例えばヘッダー・フッターといった部分を毎ページに配置したい際、1つのレイアウトファイルにまとめておき、それらを各ページが利用するようにすれば、ページコンポーネントは個別の中身だけを記述すればよい仕組みになっている。
レイアウト機能を使う際は、layout/ディレクトリに*.vueファイルを配置することでレイアウトファイルとして認識される。

my-nuxt-app
├ layouts/
│ ├ default.vue  # デフォルトのレイアウト
│ └ admin.vue  # admin用のレイアウト...

default.vueという名前で記述したレイアウトファイルは、特定のレイアウトが適用されていない全てのページに適用されるデフォルトレイアウトとして機能する。

layouts/default.vue
<template>
    <header>
        <h1>共通ヘッダー</h1>
    </header>
    
    <!-- ページコンテンツはここに差し込まれる -->
    <slot />

    <footer>
        <p>共通のフッター</p>
    <footer/>
</template>

<slot />タグには後述するNuxtLayoutコンポーネントの子要素が挿入される。
このレイアウトを呼び出して適応させるには、NuxtLayoutコンポーネントを利用する。

<template>
    <div>
        <NuxtLayout>
            <NuxtPage />
        </NuxtLayout>
    </div>
</template>

ページごとに利用するカスタムレイアウト

カスタムレイアウトを定義して、そのレイアウトを各ページで利用したい場合はdefinePageMeta()関数を利用する。

layouts/admin.vue
<template>
    <div>
    これはアドミンページ用のレイアウトです
    <slot />
    おわり
    </div>
<template/>
pages/admin.vue
<script setup lang="ts">
definePageMeta({
    layout: "admin"
});
</script>
<template>
    <div>ページコンテンツ</div>
</template>
HIR0HIR0

HTTPリクエストによるデータの取得

$fetch()

$fetchはNode.jsで標準的に利用でき、HTTPリクエストを送信することが可能。

<script setup lang="ts">
const data = ref()
const res = await $fetch('https://hogehoge.com/data')
data.value = await res.json()
</script>

useAsyncData()

useAsyncData関数はサーバーサイド・クライアントサイドの両方でデータ取得を簡単に行うための仕組み(らしい。正直まだよくわかってない)。
第一引数にキーを指定でき、このキーが同じuseAsyncData()の実行結果はキャッシュされることで、APIの呼び出し回数の節約に貢献する。

useAsyncData(
    キー文字列,
    (): Promise<取得データの型> => {
        // データ取得処理
        return 取得データ;
    ),
    オプションのオブジェクト
);

useFetch()

useFetch()関数はNuxtで更にデータ取得を簡単に行うための仕組み。
取得したデータはdataプロパティに格納され、リアクティブなデータとして保持される。

useFetch()の引数、オプション

引数名 内容
query URLに付与されるクエリパラメータ
method HTTPメソッド
body リクエストボディ
pick 戻り値から一部のフィールドデータだけを取り出したい場合に使う
transform レスポンスを任意の形に加工したい場合に使う
lazy データの取得を後回しにして画面を先に読み込ませる

useFetch()の戻り値オブジェクト

プロパティ名 内容 データ形式
data 取得したデータがリアクティブに格納される 初期値はnull
pending データの取得が完了したかどうかを表す ローディング中はtrue, 完了後false
error データ取得に失敗した際にエラーオブジェクトが格納される
refresh データを再取得する関数 非同期関数
useFetch(
    アクセス先のURL,
    オプションオブジェクト
);
HIR0HIR0

よく使う処理を再利用可能な状態にする

Nuxtではプロジェクト内にcomposables/ディレクトリを作成し、その中にuse◯◯.tsというファイルを用意すると、どのコンポーネントからもインポート無しで呼び出すことができる仕組みがある。
これはComposableという仕組みで、コンポーネントでよく使う状態管理や関数を別ファイルにまとめておくことで再利用可能とすることを目的としている。

例えば以下のようにコンポーザブルを定義すると、各コンポーネントはuseCounter()を呼び出すだけで、この中のincrement()decrement()のロジックを使い回せるようになる。

composables/useCounter.ts
// 関数名はファイル名と同じにする
export function useCounter() {
    const count = ref(0)
    function increment() {
        count.value++
    }

    function decrement() {
        count.value--
    }

    return {
        count,
        increment,
        decrement
    }
}