やりたかった処理
現在自分で使う用に簡単な家計簿webアプリのようなものを作っているのですが、その中でフロントエンド(Vue.js)からAWS上のREST APIを叩いて、取得した内容を即座に画面に反映させる処理を作成していました。
Vue.jsの親コンポーネントがサーバサイドよりデータを取得し、取得データを子コンポーネントに渡し子コンポーネントがチャートを描画する処理です。
参考までに、こんな感じのチャートです(支出の種別のランキングを表すドーナツチャートです)。
ところが、ログを見るとAPIからのデータ取得は成功しているにもかかわらず、画面にはデータが反映されない現象が起こりました。
この問題を解決するためインターネットでサーチをするも、あまり参考になる記事が少なかったため、ここに解決方法を記しておきます。
うまくいかなかったコード
うまくいかなかった処理は以下のようになっています。
まず、親コンポーネントで以下のようにAPIサーバからデータを取得し、dataset
という変数に取得結果を格納します。
家計簿アプリなので、取得するデータは特定の期間中の支出及び収入の一覧となっています。
axios.get(getUrl, config).then((response) => {
this.dataset = response.data.body;
})
そして、dataset
をchart-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でデータ変更が画面表示に反映されないときに参考になりそうな記事です。