127
82

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Nuxt2.12.0で新しくなったfetchについて

Last updated at Posted at 2020-03-18

Nuxt2.12.0でfetch methodが新しくなりました。

...fetch?

っていうか、fetchって使います? 多分使わないと思います。なぜならasyncDataと機能的にほぼ同じなので。fetchにできることは全部asyncDataで出来ていました。

新しくなったというか、ついに定義された真のfetch

で、2.12からは完全に新しくなりました。将来的にはむしろasyncDataを不要にしていくと思います(後述)

APIドキュメント: https://nuxtjs.org/api/pages-fetch

要点としては

  • pageComponent限定の機能ではなくなった
  • fetch methodの引数にcontextを受け取らなくなったかわりに、thisが使えるようになった(なのでpropを用いたfetchなどが可能に)
  • thisに $fetch, $fetchState が生えた
  • this.$fetch() で再実行ができるようになった

というあたりです。

fetch処理中の表示の出し分け

  data() {
    return {
      post: {}
    }
  },
  async fetch() {
    this.post = await this.$http.$get(
      `${this.api}${this.$route.params.id}`
    )
  },

fetchでapi叩いてthis.postに入れるとします。

<template>
  <p v-if="$fetchState.pending">Loading...</p>
  <p v-else-if="$fetchState.error">Error: {{ $fetchState.error.message }}</p>
  <div v-else>
    <h1>{{post.title}}</h1>
    <div>{{post.body}}</div>
  </div>
</template>

従来のページコンポーネントでは非同期処理が完了してからページ遷移・表示が行われていましたが、今回新しくコンポーネント単位になったことによりクライアントサイドで実行される場合には処理中の表示が発生します。

そこで 「実行中/エラー/実行完了」 の3つの表示を作るわけですが、$fetchStateにはその状態が自動的に入るので、template側ではこのように表示を出し分けることができます。

Frame 2.png

イメージを図にするとこんな感じでしょうか。fetchはmount前(SSR含む)とmethodを叩いたときに呼ばれます。pageComponentではないので、propの値に応じてfetchするようなコンポーネントも作りやすいと思います。

propの値でfetchする例

image.png

image.png

image.png

古いツイートなので$isFetchingとか変数名が異なってますが、propの値を使ってfetchしてSSRする例です(画像2枚目)。
fetchOnServer: false にすることで一部のコンポーネントはクライアント処理のみにするといったこともできます(画像3枚目)

仕組み

async function $fetch() {
  this.$nuxt.nbFetching++
  this.$fetchState.pending = true
  this.$fetchState.error = null
  this._hydrated = false
  let error = null
  const startTime = Date.now()

  try {
    await this.$options.fetch.call(this)
  } catch (err) {
    error = normalizeError(err)
  }

  const delayLeft = this._fetchDelay - (Date.now() - startTime)
  if (delayLeft > 0) {
    await new Promise(resolve => setTimeout(resolve, delayLeft))
  }

  this.$fetchState.error = error
  this.$fetchState.pending = false
  this.$fetchState.timestamp = Date.now()

  this.$nextTick(() => this.$nuxt.nbFetching--)
}

この辺の処理は上記のコードにある通り、fetchメソッドの実行が完了するまでは $fetchState.pending がtrueになり、fetchメソッドでエラー発生した場合には $fetchState.error にエラーオブジェクトが入るという形になっています。

つまり、fetchメソッドの中では敢えてtry catchせずエラーをそのまま投げるように書くことになります。

asyncDataとの違い

これでやっとasyncDataと住み分けができてきた感じです。

現状でfetchに無いのは context です。以前のfetchには引数に渡されていましたが今回の変更で無くなりました。

redirectやresponseのstatusCodeを設定するにはcontextが必要ですが、fetchでは使えないのでしょうか。現状では使えません。そういう処理のためには引き続きasyncDataが必要です。

Nuxt 3: Introducing fetch() hook

Context
fetch hook does not receive any context as 1st argument anymore since it has access to this.

The context will be updated to be available through this.\$ctx, this.\$config and this.\$nuxt, learn more on #25

Nuxt 3: Context changes

ですがRFCにあるように将来的には this.$ctx が生えるようになるようです。
こちらを使うことでasyncDataの役割はfetchでできるようになっていくと思います。

追記: context使えます

context、this.$nuxt.context で使えました。

  • redirectは this.$nuxt.context.redirect(path)
  • resは process.server がtrueのときに this.$nuxt.context.res に入るので設定できる感じです
127
82
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
127
82

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?