はじめに
今回はv-ifの値が子コンポーネントで定義したdataプロパティだった時はどうなるのか、といいう確認がしたい
いまだに画面描画時に処理をしたい時にbeforeCreate, created, beforeMount, mountedの内どれを使えばいいのかの判断も曖昧なので、そんな自分の一助になればと思った
加えてmethodsでsrcの値をreturnするパターンはどうなのか、ということも確認
話すこと
前回と同じで、以下コードを例にどのライフサイクルフックをつかったら、どんな挙動を示すのかを順にみていく
やりたいこと
子コンポーネントで定義するimgタグのsrc属性の内容に応じて表示する画像を変更する
OKな時
NGな時
ソースコード
親コンポ―ネント
<template> <div> <ImageChildComponent :url="url" @replace="replaceUrl" ></ImageChildComponent> </div> </template> <script> import ImageChildComponent from './ImageChildComponent.vue' export default { components: { ImageChildComponent }, data() { return { url: '', } }, methods: { replaceUrl(newUrl) { console.log(newUrl); this.url = newUrl; }, } } </script>
親コンポーネントでやっていることは前回と変わらない
子コンポーネント
<template> <div> <!-- OK時の画像 --> <div v-if="url" > <h2>OK!!!</h2> <img :src="childUrl" width=200 > </div> <!-- NG時の画像 --> <div v-else > <h2>NG...</h2> <img src="../assets/no-image.png" width=200 > </div> </div> </template> <script> export default { props: { url: { type: String, default: "", }, }, data() { return { childUrl: '', } }, beforeCreate() { console.log('beforeCreate: ', this.childUrl); // const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; // this.childUrl = newUrl; }, created() { console.log('created: ', this.childUrl); // const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; // this.childUrl = newUrl; }, beforeMount() { console.log('beforeMount: ', this.childUrl); // const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; // this.childUrl = newUrl; // console.log('beforeMount: ', this.childUrl); }, mounted() { console.log('mounted: ', this.childUrl); // const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; // this.childUrl = newUrl; // console.log('mounted: ', this.childUrl); }, methods: { getUrl() { console.log('methods(getUrl): ', this.childUrl); // const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; // this.childUrl = newUrl; // return this.childUrl; } } } </script>
<template>
でやっていることは基本的には一緒ですが、変化点は以下
- 表示するimgのsrc属性の値が子コンポーネント特有のdataプロパティ
childUrl
になっている
<script>
でやっていることも基本一緒ですが、変化点は以下
- 子コンポーネント特有のプロパティ
childUrl
を定義 - 各ライフサイクルフックで
childUrl
にnewUrl
を代入 - consoleで出力するのは
childUrl
検証方法
手順として前回同様、コメントアウトしてある箇所を随時コメントインして実行していく
デフォルト
ブラウザ
コンソール
前回同様、エラーが2つ。理由も同じなので割愛
beforeCreated
... beforeCreate() { console.log('beforeCreate: ', this.url); const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; this.childUrl = newUrl; }, ...
ブラウザ
デフォルトと同じなので割愛
コンソール
コチラもデフォルトと同じなので割愛
ここまでも前回同様
※beforeCreatedに console.log('beforeCreate: ', this.url); を書いていると常にエラーがでてくるので、これ以降はこの処理をコメントアウトする
created
created() { console.log('created: ', this.url); const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; this.childUrl = newUrl; console.log('created: ', this.url); },
ブラウザ
beforeCreateと同じ
コンソール
今回は何も表示されない
恐らくv-ifでurlがnullなので、v-else側に入っているからだと思う
そして、再インスタンス化(前回同様console.logをcreatedに追加)しても結果は変わらない
結果は割愛
created() { console.log('created: ', this.url); const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; this.$emit("replace", newUrl); // インスタンス化するために追加 console.log('created: ', this.url); },
ギモン
多分上記推測であってるはず
今回はv-elseに入って、前回はv-if側に入った点からみると
一度templateの描画、インスタンス化→urlの値が変化(前回)→再描画、インスタンス化
という流れだろうか
ただこれで行くと、前回各ライフサイクルフックでthis.urlの内容が表示されなかった点はつじつまが合わない
beforeMount
beforeMount() { console.log('beforeMount: ', this.url); const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; this.childUrl = newUrl; console.log('beforeMount: ', this.url); },
ブラウザ
createdと同じ
コンソール
createdと同じ
ギモン
createdと同じ
mounted
mounted() { console.log('mounted: ', this.url); const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; this.$emit("replace", newUrl); },
ブラウザ
created, beforeMouteと同じ
コンソール
created, beforeMouteと同じ
ギモン
created, beforeMouteと同じ
methods
ここで想定するのは以下のようなソースコード
<template> <div v-if="url" > <h2>OK!!!</h2> <img :src="getUrl()" // 変更 width=200 > </div> ... </template> <script> export default { ..., methods: { getUrl() { console.log('methods(getUrl): ', this.url); const newUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg=='; this.childUrl = newUrl; return this.childUrl; } ... } </script>
ブラウザ
created, beforeMoute, mountedと同じ
コンソール
created, beforeMoute, mountedと同じ
getUrlをv-ifで呼び出した場合
<div v-if="getUrl()" <!-- 変更 --> > <h2>OK!!!</h2> <img :src="getUrl()" width=200 > </div>
ブラウザ
コンソール
ここで初めてブラウザに表示
コンソールの流れからして、
- beforeMountまではDOMは生成されないため
getUrl
が呼ばれないためchildUrlはnull - beforeMount以降はDOMが生成され、getUrlが呼ばれる
- console3行目:1回目のDOM生成時のv-ifでのgetUrl。初回のconsole.logなので、childUrlには何も入っていない
- console4行目:1回目のDOM生成時のimg内のgetUrl。既にchildUrlが変更されているので、newUrlが出力
- console5行目:1回目のDOM生成が終わり、dataが変更されているので、mountedが呼び出される。childUrlはgetUrlで設定したnewUrlが入っている
- console6, 7行目:それぞれ2回目のv-if, img内のgertUrl呼び出し時のconsole.log。1回目のDOM生成時に設定したchildUrlがそのまま引き継がれている
参考記事
https://jp.vuejs.org/v2/guide/instance.html#ライフサイクルダイアグラム
所見
- 今回はv-ifの条件がnullでスタートしたので、ほぼno-imageの表示であまり変化が負えなかった
- とは言え、最後のgetUrの例はライフサイクルを知るのにかなりわかりやすかった
- いくつかVueのライフサイクルとは想定外の挙動をしている、、、
- 次はdataをv-ifにした上で、ライフサイクルを追ってみる