Skip to content

Commit 4d20b7d

Browse files
authored
Merge pull request #1430 from future-architect/feature
Nuxt
2 parents 3afd6d5 + fc10ca5 commit 4d20b7d

File tree

4 files changed

+114
-0
lines changed

4 files changed

+114
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
---
2+
title: "Vue.js連載始めます & Nuxtの通信パターンも見てみる"
3+
date: 2024/11/25 00:00:00
4+
postid: a
5+
tag:
6+
- Vue.js
7+
- Nuxt
8+
- フロントエンド
9+
category:
10+
- Programming
11+
thumbnail: /images/20241125a/thumbnail.png
12+
author: 澁川喜規
13+
lede: "フロントエンドフレームワークからサーバーにアクセスするパターンという記事を書いたところ、ちょっとバズったので、そういえば調べきれてなかったNuxtの話でも書こうかな、と思って調べてみた記事です。"
14+
---
15+
16+
<img src="/images/20241125a/top.png" alt="" width="800" height="378">
17+
18+
19+
Vue.js連載企画を始めます。今年は勤労感謝の日が土曜日で、勤労に感謝できなくて残念でしたね。
20+
21+
| Date | Name | Title |
22+
|:-|:-|:-|
23+
| 11/25(月) | 渋川よしき | Nuxtの通信パターンも見てみる(この記事) |
24+
| 11/26(火) | 大岩潤矢さん | Vue3・Nuxt3アプリをPWA化する方法 2024年版 |
25+
| 11/27(水) | 村田靖拓さん | 2015年頃のフロントエンジニアだってvoid(0)のワクワクを理解したい |
26+
| 11/28(木) | 永井優斗さん | Vue Fes Japan 2024報告 |
27+
| 11/29(金) | 山本竜玄さん | Deno × Vueを触ってみた(2024年冬) |
28+
29+
# Nuxtの通信パターンも見てみる
30+
31+
[フロントエンドフレームワークからサーバーにアクセスするパターン](/articles/20241111a/)という記事を書いたところ、ちょっとバズったので、そういえば調べきれてなかったNuxtの話でも書こうかな、と思って調べてみた記事です。
32+
33+
# Nuxt3の通信機能
34+
35+
Nuxt3のドキュメントには以下の3つの基本の通信のための機能があります。
36+
37+
| 関数 | 機能 |
38+
|:-|:-|
39+
| `$fetch()` | [ofetch](https://github.com/unjs/ofetch)というブラウザAPIの`fetch()`互換のライブラリの関数 |
40+
| `useAsyncData()` | データ取得のライフサイクル管理やキャッシュ管理をするラッパー |
41+
| `useFetch()` | `$fetch()` + `useAsyncData()` |
42+
43+
現在サポートされているNode.js18以降はみなオプションをつかわずに`fetch()`が使えるのに、なぜ`$fetch()`なんてものを別に用意しているかというと、単なる`fetch()`ではなく、ヘッダーを付与したりプリセットが設定できるような`create()`メソッドが使えたり、拡張されていたりします。何もしなくても、サーバー側で実行すると、ホスト名を省略できるなども設定されています。
44+
45+
https://nuxt.com/docs/guide/recipes/custom-usefetch
46+
47+
`useAsyncData()`そのものには通信機能はなく、中のコールバックで`$fetch()`を呼びます。ただし、通信をキャッシュして2度目以降は呼ばないようにしたり、通信中かどうかのフラグだったり、通信結果のデータだったりを返してくれます。単なる`async`な情報取得関数をこの中で呼ぶだけで表示管理やキャッシュが行えてしまうという優れものです。OpenAPIで作ったクライアントをラップしたりといった使い方もできるでしょう。
48+
49+
```html
50+
<script setup lang="ts">
51+
const { data, status, error, refresh, clear } = await useAsyncData(
52+
'mountains', // キャッシュのキー
53+
() => $fetch('https://api.nuxtjs.dev/mountains')
54+
)
55+
</script>
56+
```
57+
58+
`useFetch()`は、上の2つをまとめて呼ぶヘルパー関数です。コードが短くなります。
59+
60+
```html
61+
<script setup lang="ts">
62+
const { data, status, error, refresh, clear } = await useFetch(
63+
'https://api.nuxtjs.dev/mountains'
64+
)
65+
</script>
66+
```
67+
68+
これ以外に、`useAsyncData()`と、`useLazyFetch()`という派生の関数もあります。
69+
70+
# Nuxtの`useFetch()`/`useAsyncData()`のライフサイクル
71+
72+
`$fetch`単体では、通常の`fetch()`とだいたい同じなので特別なことはないのですが、他の2つは末尾にオブジェクト型でオプションを追加すると、動作が大きく変わります。例えば、`server: false`をつけると、サーバーサイドレンダリング時においても、サーバーからリクエストを行わず、ブラウザの表示後にリクエストされるようになります。
73+
74+
```ts
75+
const { data, status, error, refresh, clear } = await useFetch(
76+
'https://api.nuxtjs.dev/mountains',
77+
{ server: false } // これを追加
78+
)
79+
```
80+
81+
オプションはいろいろあります。
82+
83+
* `server`:サーバー上のデータを取得するかどうか(デフォルトは`true`
84+
* `lazy`:クライアント側のナビゲーションをブロックする代わりに、ルートをロードした後に非同期関数を解決するかどうか(デフォルトは`false`)、`true`にすると、動作が`useLazyFetch()``useLazyAsyncData()`と同じになる
85+
* `immediate``false`に設定すると、リクエストがすぐに起動できなくなります。(デフォルトは`true`
86+
* `dedupe`: すでに保留中のサーバー呼び出しがあった場合の動作
87+
* `'cancel'`: 呼び出し中の古いリクエストをキャンセルする(こちらがデフォルト)
88+
* `'defer'`: 新しい呼び出しの方をキャンセルする
89+
* `watch`: 何かしらのリアクティブを設定すると、それが変更されたときに再リクエストを行う
90+
* `default`: デフォルト値を返す
91+
92+
デフォルトではサーバー側のレンダリング時にリクエストを行います。`server: false`にすると、ブラウザからリクエストが飛ぶようになります。あるいは、そのコードが書かれたコンポーネントが[ClientOnly](https://nuxt.com/docs/api/components/client-only)コンポーネントでラップされた中に置かれていた場合は、それはすべてクライアント側でおこなれわれています。
93+
94+
`default`のデフォルト値設定と、`lazy: true`もしくは、Lazyがつく方のメソッドを使う、`immediate: false`を組み合わせると、まず初期値を返し、後から結果を返すことができます。これが`server: false`であれば前のエントリーのStale-While-Revalidateのようになりますし、`server: true`であればサーバーコンポーネントのような動きになります。
95+
96+
初期値は`default`を設定すれば最初から返せますし、`useFetch()``useAsyncData()`が返す`status`を見ることで、未ロードかどうかをハンドリングできます。
97+
98+
これらのオプションをうまく使い分けると多くのパターンが実現できることがわかります。
99+
100+
## 少し問題
101+
102+
ただ、色々試していて、サーバーアクセスする2つのコンポーネントがあった場合に、それぞれの通信でブロックしているような動作をしていました。わかりやすくするためにサーバーAPI側で1秒間のウェイトをかけていたのですが、コンポーネントが2つあると初期表示が2秒になりました。`<Suspense>`とか使ってもカバーできず、直列に待っているようでした。検索してみたら・・・[この](https://github.com/nuxt/nuxt/issues/12391)issueですかね。
103+
104+
Next.jsで同じようなプログラムを作ってみたところ、2つのコンポーネントが並列でリクエストを送っても(URLなどは変えてキャッシュされないようにして)、1秒ですみました。このあたりの並列処理とかはまだNext.jsに一日の長がありますね。
105+
106+
通信するコンポーネントが複数あると遅くなるので、一箇所で行なって`Promise.all()`で並列で待つとかをすれば良いとは思いますが・・・・
107+
108+
あと、experimentalなサーバーコンポーネントを試してみたけども、どうもクライアント側で動いているような感じでした。
109+
110+
# まとめ
111+
112+
Nuxtの通信周りのAPIをさらっとみて実験等をしてみました。これ1つで、さまざまなパターンに対応できる機能で、これはReactとかでも欲しいな、とちょっと思いました。
113+
114+
なお、最初、間違ってページ遷移時のリンクを`<NuxtLink to="遷移先">`ではなく、`<a href="遷移先">`と書いてしまい、ページ遷移後のレンダリングも全てがサーバーサイドレンダリングになってしまい、「サーバーコンポーネントと言っているReactよりもかなり前衛的ですごいじゃん!!!!」と勘違いしてしまい、方針変更してそちらについて書こうと思ってNuxt2との動作比較とかも調べたりしたのですが、`<NuxtLink>`の存在に気づいて書き換えたら、Next.js 12以前と同じような動きになって、原稿を全消ししたりしました。
9.7 KB
Loading

source/images/20241125a/top - コピー.png:Zone.Identifier

Whitespace-only changes.

source/images/20241125a/top.png

34.5 KB
Loading

0 commit comments

Comments
 (0)