エラー表示の改善
次に紹介するのは、エラー表示に関する変更点です。
エラー表示をわかりやすいものに変更
Nuxtアプリケーションの開発段階で、エラーが発生した場合、自動でエラー画面が表示されるようになっています。そのエラー画面がバージョン3.16で改善され、スタックトレースの表示など原因追及しやすい画面に変わっています。
これは、Nuxtに含まれているサーバエンジンであるNitroのエラー表示機能を、Youchに変更したのが原因です。こちらは、Nitroがバージョン2.11にアップデートした際の変更であり、その変更がNuxtにも影響しています。
カスタムエラーページをオーバーレイ表示
図6のエラー画面の右下にオーバーレイ表示されているエラー画面が、バージョン4.2で改善されたものです。それまでのエラー画面は開発者にはわかりやすいものの、実際のエラー画面がどのようなものかがすぐにはわかりませんでした。特に、カスタムエラー画面を利用している場合は、エラーごとの見え方も同時に確認したいものです。
そこで、図6の右下のように、本来のエラー画面もオーバーレイされるようになっています。このオーバーレイエラー画面はドラッグして、画面の上下左右の各辺の任意の場所に引っ付けておくことができます。
さらに、バージョン4.3で、オーバーレイされたエラー画面を最小化できるように変更されています。オーバーレイされたエラー画面上の[×]をクリックすると「Show error page」と表示されたアイコンへと変化します。もちろん、そのアイコンをもう一度クリックすると元の表示へと戻ります。
データ取得コンポーザブルの改善
次に紹介するのは、データ取得コンポーザブルに関する変更点です。Nuxtには、useFetch()とuseAsyncData()というデータ取得に関して便利なコンポーザブルがあります。
これらのコンポーザブルに関して、3.1以降、その性能改善も含めてさまざまな変更が施されています。
リアクティブキーが利用可能
useFetch()でも、useAsyncData()でも、ユニークキー文字列を指定でき、そのキー文字列がキャッシュの制御(識別)に利用されています。そのキー文字列として、リアクティブな変数が利用できるように、バージョン3.17で変更になっています。
例えばリスト1のコードです(以下のコード例は、全てuseFetch()で紹介していますが、useAsyncData()でも同じです)。
const randomKey = ref(Math.random());
const { data } = await useFetch(
"/api/getTimestamp",
{
key: computed(
() => {
return "timestampWithRandomKey_" + randomKey.value;
}
)
}
);
リスト1では、キー文字列を指定するkeyオプションが算出プロパティとなっています。その中でリアクティブな変数であるrandomKeyを利用しています。
この状態でrandomKeyの値が変更されると、自動的にキーが変わることになり、結果、キャッシュが利用されずにデータの再取得が行われます。
キャッシュの改善
このように、キー文字列は取得したデータのキャッシュに利用されています。このキャッシュの仕組みが同じく3.17で改善され、同一キーの場合は、コンポーネントまたぎでキャッシュが利用されるようになっています。
例えば、リスト2のデータ取得コードが書かれたページコンポーネントとしてfetchTimestampWithKey.vueがあるとします。キーとしてtimestampWithKeyを指定しています。
const { data } = await useFetch(
"/api/getTimestamp",
{
key: "timestampWithKey"
}
);
そして、例えば、このページからの遷移先ページコンポーネントとして、fetchTimestampWithKeySub.vueがあるとします。そこに、リスト2と同じデータ取得コードであるリスト3が記述されているとします。ポイントは、キーがリスト2と同じtimestampWithKeyだということです。
const { data } = await useFetch(
"/api/getTimestamp",
{
key: "timestampWithKey"
}
);
この場合、リスト3のfetchTimestampWithKey.vueが表示された後にfetchTimestampWithKeySub.vueが表示される際に、データ取得通信は行われず、同一キーであるtimestampWithKeyでキャッシュされたデータを再利用されます。この仕組みにより、余分なデータ通信を減らすことができます。
clearユーティリティの追加
一方で、任意のタイミングでキャッシュをクリアしたい場合もあります。その際に便利なユーティリティとして、clearが、バージョン3.11で導入されています。
例えば、リスト4のfetchTimestampWithKeySub.vueにおいて、リスト4の(1)のように、useFetch()の戻り値オブジェクトにclearプロパティを取得するコードを追記したとします。
const { data, clear } = await useFetch( // (1)
:
);
clear(); // (2)
その上で、リスト4の(2)のようにこのclearを任意のタイミングで関数として実行します。すると、取得したデータのキャッシュが削除されます。
その状態で画面遷移などで、fetchTimestampWithKey.vueやfetchTimestampWithKeySub.vueの画面を再表示させると、その時点でのデータを再取得することになります。
getCachedDataの導入
こういったキャッシュの再利用に関して、より細かい制御ができるような仕組みとして、getCachedDataオプションがバージョン3.8で導入されています。これはリスト5のようになります。
const { data } = await useFetch(
"/api/getTimestamp",
{
key: "timestampWithCachedController",
getCachedData: (key, nuxtApp, ctx) => { // (1)
return nuxtApp.payload.data[key] || nuxtApp.static.data[key]; // (2)
}
}
);
getCachedDataオプションでは、プロパティ値としてアロー関数を定義し、その引数は表3の3個となっています。
| 引数名 | 型 | 内容 | |
|---|---|---|---|
| 1 | key | string | キー文字列 |
| 2 | nuxtApp | NuxtApp | Nuxtアプリケーション(3.11で追加) |
| 3 | ctx | AsyncDataRequestContext | データリクエストの理由が格納されたオブジェクト(3.17で追加) |
第1引数のキー文字列は、useFetch()やuseAsyncData()で指定したキー文字列そのものです。
第3引数のctxであるAsyncDataRequestContextオブジェクトには、causeプロパティが定義されており、その値として表4の文字列が格納されています。
| 値 | 内容 |
|---|---|
| initial | 初期データ取得 |
| refresh:manual | refreshユーティリティの手動実行 |
| refresh:hook | フックによるrefreshの実行 |
| watch | ウォッチャーによるデータ再取得 |
戻り値はundefined、またはデータそのものです。undefinedの場合はキャッシュがないものとみなし、非同期通信によるデータの取得が行われます。一方、undefined以外がリターンされた場合はその値をキャッシュされたデータとみなし、非同期通信は行いません。
なお、getCachedDataのアロー関数の引数は、3.8でgetCachedDataが導入された時点ではkeyのみでした。これが、バージョン3.11で第2引数のnuxtAppが、バージョン3.17で第3引数のctxが追加されています。
このうち、第2引数のnuxtAppであるNuxtAppオブジェクトが追加されたのは、getCachedDataのアロー関数内のコードにほぼ必要なオブジェクトだからです。
それが、リスト5の(2)のコードです。データ取得において、キャッシュされたデータはNuxtAppオブジェクト内に格納されています。それを取り出しているのが(2)です。
具体的には、ハイドレーションにおけるキャッシュデータは、NuxtAppのpayloadプロパティに、ハイドレーションしていない場合はstaticプロパティに、第1引数のkeyをキーとして格納されています。
そのため、一旦両方のデータを取得した上で、そのどちらかをリターンするコードとなっています。そして、両方ともが存在しない場合は、自動的に戻り値がundefinedとなり、データの取得が行われるようになります。
getCachedDataによるTTL制御
このgetCachedDataを利用すると、より細かいキャッシュ制御が行えるようになります。
例えば、一度取得したデータに関して、10秒間はキャッシュしたデータを利用する一方で、10秒以上経過していれば再取得するといったコードも記述可能となります。いわゆるキャッシュのTTL(Time to Live)の制御です。
これは、リスト6のコードとなります。コメント形式で解説を記載しているので参考にしてください。
const { data } = await useFetch(
"/api/getTimestamp",
{
key: "timestampWithCachedController",
transform(input) {
return {
...input,
//transformオプションを利用してフェッチデータにその時点の日時を追加。
fetchedAt: new Date()
}
},
getCachedData: (key, nuxtApp, ctx) => {
//キャッシュデータを取得。
const data = nuxtApp.payload.data[key] || nuxtApp.static.data[key];
//キャッシュデータを戻り値変数とする。
let returnData = data;
//キャッシュデータがundefinedでなければ…
if(data) {
//fetchedAtを元にDateオブジェクトをexpirationDateとして生成。
const expirationDate = new Date(data.fetchedAt);
//expirationDateを10秒後に設定。
expirationDate.setTime(expirationDate.getTime() + 10000)
//現在の日時がexpirationDateよりあとかどうかの値をisExpiredとする。
const isExpired = expirationDate.getTime() < Date.now()
//現在の日時がexpirationDateよりあとならば…
if(isExpired) {
//戻り値をundefinedに変更。
returnData = undefined;
}
}
//戻り値としてキャッシュされたデータかundefinedをリターン。
return returnData;
}
}
);
まとめ
Nuxtのバージョン4.3までの変更点をテーマごとに紹介する本連載の第1回目は、いかがでしたでしょうか。
今回は、概説と、新しいプロジェクト構成、エラー表示の改善点、データ取得の変更点を紹介しました。
次回は、コンポーザブルやコンポーネントに関して、新たに追加されたもの、変更されたものを紹介します。
