JavaScript
AWS
vue.js
axios

Vue.jsで外部APIから取得したデータが反映されないときの対処法


やりたかった処理

現在自分で使う用に簡単な家計簿webアプリのようなものを作っているのですが、その中でフロントエンド(Vue.js)からAWS上のREST APIを叩いて、取得した内容を即座に画面に反映させる処理を作成していました。

以下の図のような処理です。

無題.png

Vue.jsの親コンポーネントがサーバサイドよりデータを取得し、取得データを子コンポーネントに渡し子コンポーネントがチャートを描画する処理です。

参考までに、こんな感じのチャートです(支出の種別のランキングを表すドーナツチャートです)。

無題.png

ところが、ログを見るとAPIからのデータ取得は成功しているにもかかわらず、画面にはデータが反映されない現象が起こりました。

この問題を解決するためインターネットでサーチをするも、あまり参考になる記事が少なかったため、ここに解決方法を記しておきます。


うまくいかなかったコード

うまくいかなかった処理は以下のようになっています。

まず、親コンポーネントで以下のようにAPIサーバからデータを取得し、datasetという変数に取得結果を格納します。

家計簿アプリなので、取得するデータは特定の期間中の支出及び収入の一覧となっています。


親コンポーネント

axios.get(getUrl, config).then((response) => {

this.dataset = response.data.body;
})

そして、datasetchart-componentという子コンポーネントに引き渡します。


親コンポーネント

<chart-component :dataset="dataset"></detail-component>


子コンポーネントでは、引き受けた値をドーナツチャートにして表示します


子コンポーネント

Vue.component('chart-component', {

template: `
<div class="summary-content">
<canvas id="pieChart"></canvas>
</div>
`
,
data: function () {
return {
//チャートの描画するデータを保持
"dataList": [],
//チャートの描画するラベルを保持
"labelList": [],
//チャートの描画色を保持
"colorList": []
}
},
props: [
"dataset"
],
methods: {
/*
* 変数の初期化
*/

init() {
this.dataList = [];
this.labelList = [];
this.colorList = [];
},

/*
* ドーナツチャート表示用のデータを作成
*/

editPieChartData() {
//チャート用のデータを整える処理ですが、詳細は記事と関係ないので省略
},

/*
* ドーナツチャートの描画
*/

createPieChart() {
//チャートを描画する処理ですが、詳細は記事と関係ないので省略
}
},
created() {
console.log(this.dataset) // <= ここでログ出力
this.init();
this.editPieChartData();
this.createPieChart();
},
})


propsでAPIより取得した収入支出データを受け取ったら、createdでいくつかの関数を呼び出してチャートを描画しようとしています。

ところが、チャートは描画されないにも関わらず、引き受けたdatasetの値をcreated()直後にログに出してみてみると(ソースコード内のコメント参照)、きちんと値が入っていました。


解決方法

悩んだ末、watchを使うと解決することが分かりました。

propsで受け取った値はcreatedの時点では空であることがあるため、中身が空でなくなった時点で処理をするように変更します。

以下のように、子コンポーネント内で親から渡されるdatasetの値をwatchして変更時にチャート作成関数を呼び出すようにすることで、きちんとデータが画面表示に反映されるようになりました。


子コンポーネント

watch: {

dataset: function () {
// チャート作成関数を呼び出し
this.init();
this.editPieChartData();
this.createPieChart();
},
},


インターネットでサーチしてみると...

Vue.jsではデータの変更に合わせて画面が切り替わらない現象がよくおこるらしく、その解決方法として、$forceUpdateを使えばいいというもの、配列の追加削除には$setを使うようにすればいいというもの...などが出てきましたが、この記事のように親子間でデータを引き渡す場合についてはそれらの方法では解決せず、watchを使うのが正解のようです。

参考までに、以下がVue.jsでデータ変更が画面表示に反映されないときに参考になりそうな記事です。