少し詳しく読み解いてみる Nuxt TypeScript での asyncData とその周辺

こんにちは。UI/UXデザインを担当しているsadakitchenです。
最近はWebのフロントエンドも携わっています。

バーチャルキャストのWebフロントでは Nuxt.js や vue を活用しており、パフォーマンスの高いアプリケーションを構築しています。
更に、 TypeScript によって型安全性による恩恵を得るために Nuxt TypeScript を使っています。
(参考記事:nuxt.js による UX/DX フレンドリーな Web サービス開発
今回は Nuxt TypeScript でよく使っているメソッド asyncData とその周辺について少し詳しく読み解いてみます。

なお、Nuxt&TypeScriptの環境構築については本記事では取り扱いません。
以下のような記事を参照してみてください。
3分でつくる2019年版 Nuxt.js TypeScript 開発環境設定(Qiita)

この記事の対象者

  • Nuxt.js を触ったことがあるが、深堀りしたことはない人
  • TypeScript は使っているが、Nuxt.js はあまり触ったことがない人

環境

  • Nuxt v2.12.2
    • @nuxt/typescript-build v0.6.6
    • @nuxt/typescript-runtime v0.4.8
    • nuxt-property-decorator v2.7.2
    • @nuxt/http v0.5.1

サンプルコード

SSR (universal) モードの Nuxt のページコンポーネントで、asyncData メソッドから API を叩いて、その結果を返すようなものを作ります。
次のコードは HogePage ページコンポーネントをクエリ id を含んで表示すると、 json データを返す API を叩き、stringが変える想定の作りになっています。

深堀りしてみる

では各コード深堀りしていきます。

TypeScriptを使う際に lang="ts" と記述しています。
変数を扱う際に string や number といった「型」を明示的に使えるようになり、エラーチェックがより厳格になります。

nuxt-property-decorator とは、 vue-property-decorator に加え、 Nuxt の独自のメソッドやプロパティなどもデコレートしてくれるモジュールです。
このモジュールを使用することで、クラスベースでの記述が可能になり、ComponentPropなどをクラスの構成要素(クラスメンバ)として、@Component@Propという形で見通しよく記述することができます。(クラスに対して直接プロパティを定義できる)
nuxt-property-decorator の依存関係は以下のようになります。

デコレーターとは?

クラス宣言やメソッド、アクセサ、プロパティ、パラメーターに結び付けられる特別な宣言の一種
と説明されますが、もう少しわかりやすくすると、
「あるコードを他のコードで内包しつつ実行するもの」です。

例えば、
あるコードが Hello,world. を返す場合、
他のコードで内包していると、Hello,world. を含んで返す実装ということになります。

JavaScriptでは「@」をつけて記述することで表現できます。

なお、 Nuxt TypeScript でデコレーターを扱う場合は tsconfig.json の compilerOptions に
"experimentalDecorators": true, と記述する必要があります。

デコレーター、非常に説明が膨大なため、この記事ではサンプルコードの実装に関わる部分まで解説します。

asyncData の 引数 query と $http の型を定義するために読み込んでいます。

Component を クラス宣言 するために、デコレーターを利用する記述です。
この記述により HogePage クラスを Vueコンポーネントとして扱うことになります。

今回APIを叩くことで、非同期データを扱うことになるため、 async を追加しています。
asyncData内部には await が入ります。

asyncDataの第一引数には context オブジェクトが入るのですが、その中から使用するキーだけを記述しています。
今回はクエリの id を取得したいため、 route.query のエイリアスとなる query 、非同期処理を行うためのHTTPモジュール $http を記述しています。

返り値は非同期処理となるため、Promiseで返しています。

asyncDataとは?

asyncData はサーバーからのデータを非同期で取得し、 Nuxt.js のコンポーネント内で扱う準備をするメソッドです。
以下の特徴があります。

  • ページコンポーネントでのみ実行される
  • ページ表示時に毎回実行される(Nuxt.jsのライフサイクルイベント)
  • 第一引数に context オブジェクトが入る
  • asyncData内で this は使えない
  • asyncDataの返り値は data と統合される
  • 非同期の場合、asyncDataの返り値は Promise となる

またasyncDataがNuxtフレームワーク内で実行される順番(ライフサイクル)は以下のようになっています。
詳しくはVue.js と Nuxt.js のライフサイクル早引きメモ(Qiita)を参照ください。

contextとは

特定のライフサイクルで使用できるオブジェクトです。
様々なキーが入っています。

クライアントサイド、サーバーサイド共通

  • app
  • store
  • route
  • params
  • query
  • env
  • isDev
  • isHMR
  • redirect
  • error

クライアントサイドのみ

  • from
  • nuxtState

サーバーサイドのみ

  • req
  • res
  • beforeNuxtRender

なお、Nuxt.jsのプラグインによっては、 $http$i18n というように $ をつけて参照することができます。

HTTPモジュールを利用して、APIを叩き、返ってきた title キーを含む json 形式の中から title データを返しています。
API を叩く際のモジュールは http ではなく、 axios でも構いません。
なお HTTPモジュール には axios と比較してこのような違いがあります。

  • 軽量
  • fetch API を利用するので service worker との親和性が向上
  • node.js 側は node-fetch を用いてほぼロジックなしで対応

(参考記事 nuxt.js は axios を捨てて ky になる様子(Qiita) )

IEを対象としないサイトの場合は、HTTPモジュールを使うのがよいのではないでしょうか。

proxyについて?

なお余談ですが、外部ドメインのAPIを叩いた際に CORS に関するエラーが発生する場合があります。
その際は @nuxtjs/proxy でプロクシを介してアクセスすることでエラーを回避できます。
以下サンプルコードを記載します。

注意点として、nuxt generateで静的なウェブアプリケーションとしてビルドした際には使用できません。
本番ではきちんとサーバー側で CORS の設定を行いましょう。

まとめ

以上のように asyncData とその周辺を読み解いて見ました。
重要なポイントとしては以下となると思います。

  • デコレータ nuxt-property-decorator を使うことでVueコンポーネントを拡張できる
  • asyncDataの引数 context オブジェクトには Vue に関する便利なキーが入っている
  • asyncDataの返り値は Vue コンポーネントの data と統合される
  • CORSの場合は @nuxtjs/proxy を使う

Nuxt.js は非常に強力なフレームワークで使いこなすのがとても大変です。
が、公式ドキュメントを読みつつ、コードを直接見ていくと、気づかなかった振る舞いを見つけることもできるとおもいます。
一つ一つ内容を読み込み、振る舞いを理解することで、使いこなせる第一歩になるのではないでしょうか。