brand logo

ドキュメント

callOnce

SSR または CSR 中に指定された関数やコードブロックを一度だけ実行します。

このユーティリティは Nuxt v3.9 から利用可能です。

目的

callOnce 関数は、以下の状況で指定された関数やコードブロックを一度だけ実行するために設計されています:

  • サーバーサイドレンダリング中(ハイドレーション時は除く)
  • クライアントサイドのナビゲーション中

これは、イベントのログ記録やグローバルな状態の設定など、一度だけ実行すべきコードに役立ちます。

使用法

callOnce のデフォルトモードは、コードを一度だけ実行することです。例えば、コードがサーバーで実行された場合、クライアントでは再度実行されません。また、クライアントで callOnce を複数回呼び出しても、例えばこのページに戻ってきた場合でも再度実行されません。

app.vue
const websiteConfig = useState('config')

await callOnce(async () => {
  console.log('これは一度だけログに記録されます')
  websiteConfig.value = await $fetch('https://my-cms.com/api/website-config')
})

初回のサーバー/クライアントの二重読み込みを避けつつ、すべてのナビゲーションで実行することも可能です。そのためには、navigation モードを使用することができます:

app.vue
const websiteConfig = useState('config')

await callOnce(async () => {
  console.log('これは一度だけログに記録され、その後すべてのクライアントサイドナビゲーションで実行されます')
  websiteConfig.value = await $fetch('https://my-cms.com/api/website-config')
}, { mode: 'navigation' })

navigation モードは Nuxt v3.15 から利用可能です。

callOncePinia モジュール と組み合わせてストアアクションを呼び出すのに便利です。

こちらも参照 getting-started > state-management

callOnce は何も返しません。SSR 中にデータフェッチを行いたい場合は、useAsyncData または useFetch を使用してください。

callOnce は、セットアップ関数、プラグイン、またはルートミドルウェアで直接呼び出すことを意図したコンポーザブルです。これは、ページがハイドレートされる際にクライアントで関数を再度呼び出さないように、Nuxt ペイロードにデータを追加する必要があるためです。

callOnce (key?: string, fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void>
callOnce(fn?: (() => any | Promise<any>), options?: CallOnceOptions): Promise<void>

type CallOnceOptions = {
  /**
   * callOnce 関数の実行モード
   * @default 'render'
   */
  mode?: 'navigation' | 'render'
}

パラメータ

  • key: コードが一度だけ実行されることを保証するためのユニークなキー。キーを指定しない場合、callOnce のインスタンスのファイルと行番号にユニークなキーが生成されます。
  • fn: 一度だけ実行する関数。非同期であることも可能です。
  • options: モードを設定します。ナビゲーション時に再実行する (navigation) か、アプリのライフタイムで一度だけ実行する (render) かを選択します。デフォルトは render です。
    • render: 初回レンダリング時に一度実行(SSR または CSR) - デフォルトモード
    • navigation: 初回レンダリング時とその後のクライアントサイドナビゲーションごとに一度実行

tips

このセクションは公式ドキュメントの翻訳ではなく、本サイト独自の補足記事です。

NuxtのcallOnceとは?何が嬉しいのか

Nuxtアプリケーションを開発していると、サーバーサイドレンダリング(SSR)やクライアントサイドレンダリング(CSR)で「ある処理を一度だけ実行したい」場面がよくあります。例えば、初期設定の読み込みやログの記録、グローバルな状態の初期化などです。

しかし、NuxtはSSRとCSRの両方でコードが実行されるため、単純に関数を呼ぶだけでは二重実行されてしまうことがあります。これが原因でパフォーマンスの低下や意図しない副作用が起きることも。

そんな課題を解決するのが、Nuxtが提供するcallOnceというユーティリティです。callOnceを使うと、SSRやCSRのどのフェーズでも指定した関数を「一度だけ」実行できるため、二重実行のリスクを防ぎつつ効率的に処理を管理できます。


まず結論:callOnceのポイント

  • 一度だけ実行:SSRまたはCSRの初回レンダリング時に指定関数を一度だけ実行する
  • モード切替可能:初回レンダリングのみ(renderモード)か、クライアントサイドのナビゲーションごとに実行(navigationモード)を選べる
  • 非同期対応:非同期関数も問題なく扱える
  • キー管理:ユニークキーで複数の呼び出しを区別可能
  • 返り値なし:結果を返さないため、データ取得はuseAsyncDataなどと併用推奨
  • 主にセットアップ関数やプラグインで利用:ページのハイドレーション時に再実行されないよう設計されている

いつ使うべきか?使わない方がよいケースは?

使うべきケース

  • 初期設定の読み込み
    例:APIからの設定情報を一度だけ取得してグローバルステートに保存したい場合

  • ログやイベントの一回限りの記録
    例:ユーザーがページを初めて訪れた時のログを一度だけ送信したい

  • クライアントサイドのナビゲーションごとに一度だけ実行したい処理
    例:ページ遷移ごとに特定の初期化処理を行いたい場合(navigationモード)

使わない方がよいケース

  • データフェッチで結果を利用したい場合
    callOnceは返り値を返さないため、取得したデータを扱いたいならuseAsyncDatauseFetchを使うべきです。

  • 頻繁に実行したい処理
    毎回のレンダリングやユーザー操作ごとに処理を実行したい場合はcallOnceは適しません。

  • コンポーネントのライフサイクルに依存する処理
    callOnceはセットアップ関数やプラグイン向けで、コンポーネントのマウントやアンマウントに依存する処理には向きません。


実務でよくあるユースケースとサンプルコード

1. APIからの設定情報を一度だけ取得してグローバルステートに保存

const config = useState('appConfig')

await callOnce(async () => {
  const data = await $fetch('https://api.example.com/config')
  config.value = data
})

この例では、サーバーサイドまたはクライアントサイドの初回レンダリング時にAPIから設定を取得し、グローバルステートに保存します。以降は再取得されません。

2. ユーザーの初回訪問時にログを一度だけ送信

await callOnce(() => {
  console.log('ユーザーが初めて訪れたことをログに記録')
  // ここでログ送信APIを呼ぶことも可能
})

ログの重複送信を防ぎたい場合に有効です。

3. クライアントサイドのページ遷移ごとに一度だけ処理を実行(navigationモード)

await callOnce(async () => {
  console.log('ナビゲーションごとに一度だけ実行される処理')
  // ページ遷移ごとに必要な初期化処理など
}, { mode: 'navigation' })

navigationモードを使うと、初回レンダリング時だけでなく、クライアントサイドのナビゲーションごとに一度だけ処理を実行できます。


よくある落とし穴・注意点

SSRとCSRの違いによる二重実行の誤解

NuxtはSSRでHTMLを生成し、その後クライアントでハイドレーションを行います。この過程で同じコードがサーバーとクライアントで実行されるため、単純に関数を呼ぶと二重実行されることがあります。callOnceはこれを防ぐために設計されていますが、使い方を誤ると期待通りに動かないことも。

Hydration時の再実行を防ぐ

callOnceはNuxtのペイロードに実行済みの情報を保持し、クライアントのハイドレーション時に再度実行しないようにしています。したがって、callOnceはセットアップ関数やプラグインで呼び出すのが適切です。コンポーネントのマウント時に使うと意図しない挙動になる可能性があります。

パフォーマンスへの影響

callOnce自体は軽量ですが、実行する関数の内容によってはパフォーマンスに影響を与えることがあります。特にnavigationモードはクライアントサイドのナビゲーションごとに実行されるため、重い処理は避けるか適切に制御しましょう。

返り値がないことに注意

callOnceはPromiseを返しますが、実行した関数の結果を返すことはありません。データ取得や結果の利用が必要な場合は、useAsyncDatauseFetchを使いましょう。


まとめ

NuxtのcallOnceは、SSRやCSRの初回レンダリング時に特定の処理を一度だけ実行したい場合に非常に便利なユーティリティです。初期設定の読み込みやログ記録、クライアントサイドのナビゲーションごとの処理など、実務でよくある課題をシンプルに解決できます。

ただし、返り値がないことや使うべき場面の制限、SSRとCSRの挙動の違いによる注意点を理解した上で使うことが重要です。適切に活用すれば、Nuxtアプリのパフォーマンス向上やコードの明確化に大きく貢献します。