🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Q&A

解決済

2回答

1992閲覧

Vueのcomputedプロパティのgetterの役割について

takutsu

総合スコア3

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

0グッド

0クリップ

投稿2021/01/16 09:55

編集2021/01/17 10:13

Vueのcomputedプロパティのgetterの役割についての質問です。

親コンポーネントと子コンポーネントの値の受け渡しについて調べておりますが、
getterの役割がよく分かりません。

getter部分をコメントアウトして実行すると、[Vue warn]: Getter is missing for computed property
が出ますが、入れても入れなくても同じ動きをします。

今回の例ですと、setteremitするイメージは分かっているつもりですが、getterは何をしているのか、getterreturnされたthis.valueは、どこが受け取っているかが分からず、質問させていただきました。

以下、getterありgetterなしのgifになります。

【getterあり】
getterあり

【getterなし】
getterなし

該当のソースコード

【parent.vue】

vue

1<template> 2 <div class="container"> 3 <div> 4 <h2>入力フォーム</h2> 5 <span>ID</span> 6 <child v-model="input" /> 7 </div> 8 <div> 9 <h2>入力内容</h2> 10 <span>{{ input }}</span> 11 </div> 12 </div> 13</template> 14 15<script> 16import child from './child'; 17 18export default { 19 components: { 20 child, 21 }, 22 data() { 23 return { 24 input: '', 25 }; 26 }, 27}; 28</script>

【child.vue】

vue

1<template> 2 <input v-model="inputValue" type="text" /> 3</template> 4 5<script> 6export default { 7 props: { 8 value: { 9 type: String, 10 default: '', 11 }, 12 }, 13 computed: { 14 inputValue: { 15 set(value) { 16 // console.log('set通過'); 17 // console.log('value:' + value); 18 // console.log('this.value:' + this.value); 19 this.$emit('input', value); 20 }, 21 get() { 22 // console.log('get通過'); 23 // console.log('this.value:' + this.value); 24 return this.value; 25 }, 26 }, 27 }, 28}; 29</script>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2021/01/17 05:24 編集

何が分からないのか分からないので、参考までに何が起こっているのかだけ書いておきます。 この例ではchildコンポーネントのinputValueプロパティが算出プロパティとして定義されています。 算出プロパティにはgetterが必須ですが、inputValueプロパティには存在していないので警告が出ています。 またinputValueプロパティはテンプレート上ではinput要素のvalueに双方向バインド(v-model)されているので、input要素の内容がinputValueプロパティと連動しているということになります。 そしてinputValue算出プロパティにはあまり使用されないsetterがあるので、input要素の内容が変更される度にinputValue算出プロパティのsetterが呼ばれます。 setterの中では引数でinput要素の内容が入ってきて、これをinputイベントとしてemitしています。 childコンポーネントのinputイベントはparentコンポーネントが購読し、内容をparentコンポーネントのinputプロパティに設定している(v-modelの意味)ので、結果的にテンプレート上のspan要素の内容テキストにも反映されます。 つまり、childコンポーネントのinput要素の内容はinputイベント発行時にそのまま内容がparentコンポーネントのinputプロパティに設定されてるので、childコンポーネントのinput要素の初期表示を除きgetterが使用されていないということです。 ご参考までに。
takutsu

2021/01/17 10:10 編集

不明瞭な質問の中で、ご丁寧に解説いただきありがとうございます。 setterとgetterの中に、console.log('set通過')といったコードを入れて実行すると、以下のようになりました。 ページアクセス時:getterのみ テキスト入力時、setter→getter 今回の例ですと、setterでemitするイメージは分かっているつもりですが、getterは何をしているのか、getterでreturnされたthis.valueは、どこが受け取っているかが分からず、質問させていただきました。
退会済みユーザー

退会済みユーザー

2021/01/17 15:17

変化のあったコンポーネントをレンダリングするときです。 今回のケースではchildコンポーネントでinputValueプロパティがテンプレート上のinput要素のvalueに双方向バインド(v-model)されていて、input要素に変化があった際にsetterが呼ばれます。 setterの中からこのコンポーネントinputイベントが発行されたため、それを購読しているparentコンポーネントのinputプロパティに反映されます。 ただinputプロパティに反映されると、双方向バインドなので、その値がchildにも反映され、レンダリングが発生し、結果としてgetterが呼ばれるということです。 parentコンポーネントのv-modelによるバインドは v-bind:value="input" v-on:input="input=$event" に分解できるのですが、v-bindを消してあげればレンダリングは発生せず、getterも呼ばれません。
takutsu

2021/01/18 04:16

ご回答いただきありがとうございます。 細かく分解して説明いただいたおかげで、getterの挙動が分かってきました。 回答にご記入いただければ、ベストアンサーにさせていただきたいと思います!
guest

回答2

0

ベストアンサー

子コンポーネントにあるinput要素のvalueに双方向バインドしている算出プロパティinputValueのgetterが何のために存在し、どういうときに呼ばれるのかについて説明します。

getter処理の明示的呼び出し

この挙動を分かりやすくするために、まずは、親コンポーネントのtemplateに

vue

1<button @click="input='hoge'">hoge</button>

という内容を加えてみてください。読めば分かるとおり、親コンポーネントにhogeボタンが追加され、そのボタンをclickすると、親コンポーネントのinputプロパティが'hoge'に変わるようになります。

では、これを実際に動かすとどうなるのか見てみます(回答の最後にそのまま動くコード全文を載せておきます)。すると、いつもどおりの画面にボタンが追加されてます。追加されたhogeボタンを押すと、入力内容の下の文字列がhogeになるところまでは想定どおりだと思うのですが、同時に子コンポーネントの入力フォームの内容もhogeになっています

入力フォームの内容もhogeになった理由

理由の説明はなかなか大変です。

  1. 親コンポーネントのinputプロパティが'hoge'に変わる
  2. (親要素のtemplateが<child v-model="input" />となっている=子コンポーネントが親コンポーネントのinputプロパティと双方向バインドされている)
  3. bindしている子コンポーネントのvalueプロパティも'hoge'に変わる
  4. (子コンポーネントの算出プロパティinputValueのgetterが子コンポーネントのvalueプロパティに依存している=子コンポーネントのvalueプロパティが変わると算出プロパティinputValueにbindしている要素は再描画しないといけない)
  5. input要素が算出プロパティinputValueにbindしているので子コンポーネントを再描画する
  6. input要素のvalueプロパティを設定すべく、算出プロパティinputValueのgetterが呼ばれる
  7. getterは子コンポーネントのvalueプロパティの値'hoge'を返す
  8. 子コンポーネントの入力フォームの内容もhogeになる

長々と書きましたが、
getterを呼ぶのはvue自身で、bindされた要素の属性に設定するたにgetterを読んでいます。
タイミングは再描画のときで、このタイミングはbindなどの依存関係によって決まります。

子コンポーネントの入力フォームの内容を直接変えた場合

最後に、子コンポーネントの入力フォームの内容を直接変えた場合の説明です。
ある程度理解されているようなので、端折りますが、emitされたevent.target.valueがそのまま親コンポーネントのinputプロパティに入って、以降は同じです。ただ再描画の際に取得したinputValueの値がinput要素のvalueの内容とすでに同じなので、何も起こらないだけです。

実験コード(全体)

HTML

1<!DOCTYPE html> 2<html lang="ja"> 3 4<head> 5 <meta charset="utf-8"> 6 <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> 7 <script> 8 const child = { 9 template: ` 10 <input v-model="inputValue" type="text" />`, 11 props: { 12 value: { 13 type: String, 14 default: '', 15 }, 16 }, 17 computed: { 18 inputValue: { 19 set(value) { 20 console.log('set通過'); 21 console.log('value:' + value); 22 console.log('this.value:' + this.value); 23 this.$emit('input', value); 24 }, 25 get() { 26 console.log('get通過'); 27 console.log('this.value:' + this.value); 28 return this.value; 29 }, 30 }, 31 }, 32 }; 33 const parent = { 34 template: ` 35 <div class="container"> 36 <div> 37 <h2>入力フォーム</h2> 38 <span>ID</span> 39 <child v-model="input" /> 40 </div> 41 <div> 42 <h2>入力内容</h2> 43 <span>{{ input }}</span> 44 </div> 45 <!-- これ追加 --> 46 <button @click="input='hoge'">hoge</button> 47 </div>`, 48 components: { 49 child, 50 }, 51 data() { 52 return { 53 input: '', 54 }; 55 }, 56 }; 57 window.addEventListener('DOMContentLoaded', function() { 58 new Vue({ 59 el: '#app', 60 components: { 61 parent, 62 }, 63 }); 64 }); 65 </script> 66</head> 67 68<body> 69 <div id="app"> 70 <parent></parent> 71 </div> 72</body> 73 74</html>

投稿2021/01/18 06:21

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takutsu

2021/01/18 13:29

ご回答いただきありがとうございます。 サンプルコードまで作っていただき、理解が深まりました。 拙い質問に対し、丁寧に対応いただきとても助かりました!
guest

0

computed: { inputValue() { return this.value }, },

参照するだけならこんな感じで、set/getを省略できる。
しかし、setを使用する場合は、関数ではなくオブジェクトを渡すので
明示的にgetされる場合はどう処理するかを書いてあげる必要がある。
(※参照するだけパターンは省略形と考えた方がよさそう)

投稿2021/01/17 10:46

mikkame

総合スコア5036

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

takutsu

2021/01/18 04:12

ご回答いただき、ありがとうございます。 このような書き方もできるということを知ることができました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問