質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.48%
Vue.js

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

Vue CLI

Vue CLIは、Vue.jsでアプリケーション開発を行うためのコマンドラインインタフェース(CLI)に基づいた開発ツールです。インタラクティブなプロジェクトの雛形や設定なしで使用できるプロトタイプの作成など、さまざまな機能が用意されています。

Q&A

解決済

2回答

7683閲覧

親コンポーネントでのデータの変更を子コンポーネントで全て検知したい

panamax

総合スコア22

Vue.js

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

Vue CLI

Vue CLIは、Vue.jsでアプリケーション開発を行うためのコマンドラインインタフェース(CLI)に基づいた開発ツールです。インタラクティブなプロジェクトの雛形や設定なしで使用できるプロトタイプの作成など、さまざまな機能が用意されています。

0グッド

1クリップ

投稿2018/11/27 14:56

VueCLI3を使っています。
親コンポーネントでのデータの変更が子コンポーネントの方で検知されるはずのところが、実際にはされておらず、その原因が分からなかったため質問させていただきます。

まず、親子コンポーネントが以下のような構成で作られています。
質問の趣旨のため、親コンポーネントはmethodsの部分のみ、子コンポーネントはpropsとcomputedの一部分のみの、出来るだけ今回の質問に関係ある部分のソースコードのみを載せます。

<親コンポーネント>

Vue

1methods: { 2 fuga() { 3 console.log("とりあえずemit成功したっぽいよ!!"); 4 if (this.lastEl1) { 5 this.lastEl = this.lastEl1; 6 console.log("lastEl1のfuga()発動したよ!!"); 7 } 8 if (this.lastEl2) { 9 this.lastEl = this.lastEl2; 10 console.log("lastEl2のfuga()発動したよ!!"); 11 } 12 if (this.lastEl3) { 13 this.lastEl = this.lastEl3; 14 console.log("lastEl3のfuga()発動したよ!!"); 15 } 16 } 17 }

<子コンポーネント>

Vue

1 2 props: { 3 lastEl: String, 4 }, 5 computed: { 6 processText() { 7 console.log("関数processTextが実行されたよ!!"); 8 if (this.lastEl === "1") { 9 処理1 10 } else if (this.lastEl === "2") { 11 処理2 12 } else if (this.lastEl === "3") { 13 処理3 14 15 <以下さらに処理が続いていく...>

このソースがどのような動きをするか簡単に説明すると、まず親コンポーネントにて定義したlastElという、"1"~"16"までの値を持つString型のデータがあるイベントによって決まります。

そうすると、子コンポーネントではlastElをpropsに登録しているため、親コンポーネントでlastElの値が変わるとともに、computedに登録した関数processTextが実行されます。(この関数では、lastElの"1"~"16"の値によってそれぞれある処理がなされます)

ここで、親コンポーネントのソースコードではlastElの値を変更するif文が3つあります。それぞれのif文に出てくるlastEl1, lastEl2, lastEl3という値は、lastElの値とは関係なくそれぞれに"1"~"16"の値のいずれかを持っており、それがlastElに代入されることになります。

そして、ここが問題なのですが、if文が3つありlastEl1〜lastEl3の値がそれぞれ異なるならば、計3回lastElの値が変更されたことになり、当然lastElの値の変更を検知した3回分、子コンポーネントの関数processTextが行われるはずです。

しかし、実際に関数processTextが実行されて処理が行われたのは一回だけでした。
これを、lastElの値が変更された回数だけ、適切に子コンポーネントの関数が実行されるようにするにはどうしたらよいでしょうか?

私が試してみた策としては、
以下のように子コンポーネントにthis.$nextTickを使ってみたりしました。
しかし、解決には至りませんでした。

Vue

1methods: { 2 fuga() { 3 console.log("とりあえずemit成功したっぽいよ!!"); 4 this.$nextTick(() => { 5 if (this.lastEl1) { 6 this.lastEl = this.lastEl1; 7 console.log("lastEl1のfuga()発動したよ!!"); 8 } 9 }); 10 this.$nextTick(() => { 11 if (this.lastEl2) { 12 this.lastEl = this.lastEl2; 13 console.log("lastEl2のfuga()発動したよ!!"); 14 } 15 }); 16 this.$nextTick(() => { 17 if (this.lastEl3) { 18 this.lastEl = this.lastEl3; 19 console.log("lastEl3のfuga()発動したよ!!"); 20 } 21 }); 22 }, 23}

Vue.jsは非同期処理をしているために同じ値(今回の場合はlastEl)を一度に複数回変更してもそれが検知されないのでしょうか?

Vue.jsのライフサイクルなども関係するのかもしれませんが、そこらへんについての知識がなく質問をしました。よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

Vue.jsは非同期処理をしているために同じ値(今回の場合はlastEl)を一度に複数回変更してもそれが検知されないのでしょうか?

こちらについては、公式ドキュメントに記載があります。

Vue は 非同期 に DOM 更新を実行します。データ変更が検出されると、Vue はキューをオープンし、同じイベントループで起こる全てのデータ変更をバッファリングします。同じウオッチャが複数回トリガされる場合、キューには一度だけ入ります。

vm.$nextTick()メソッドを使用しても、当該のデータ変更すべてが同じ(次の)イベントループに延期されるだけなので、結果は同じです。

重複した更新がはぶかれるのは、こちらのサンプルで確認できます。
質問のソースコードのように、同じデータを3回変更しますが、watchで指定した関数が実行されるのは1度だけです。
コンソールには最後の変更(changed: null -> 3)だけが表示されます。

親コンポーネントで(if文のたびに)子コンポーネントのメソッドを実行することもできますが、vm.$refsはリアクティブではない(更新されない)ので微妙かもしれません。

いずれにせよ、panamaxさんの目指している実装のゴールに対して、設計からアプローチを変えた方がいいかもしれません。

投稿2018/11/27 16:05

NozomuIkuta

総合スコア1260

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

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

0

computedプロパティは文字通りstateやpropsから「計算される」値を(副作用のない純粋な)関数によって宣言的に定義するもので、その関数がいつ何回呼ばれるかに依存したプログラムは推奨されません。

「変更を検知する」というセマンティクスに合ったwatchプロパティを使うべきです。

そして、ここが問題なのですが、if文が3つありlastEl1〜lastEl3の値がそれぞれ異なるならば、計3回lastElの値が変更されたことになり、当然lastElの値の変更を検知した3回分、子コンポーネントの関数processTextが行われるはずです。

しかし、実際に関数processTextが実行されて処理が行われたのは一回だけでした。

おそらくメソッド(今の場合fuga())の実行が終了するまでは子コンポーネントへのstateの変更を反映しないようになっているのだと思います。lastElの値が同期的に複数回変更されただけなので、子コンポーネントにとっては、最終的な値以外はどうでもいいため、わざわざ3回も自身のcomputedプロパティを計算し直す理由がありません。

これを、lastElの値が変更された回数だけ、適切に子コンポーネントの関数が実行されるようにするにはどうしたらよいでしょうか?

lastElの値が変更された回数だけcomputedプロパティが計算し直されてほしい理由はなんでしょうか?

ちなみにwatchオプションを代わりに使用してみたところやはり1度しかwatchオプションに指定した関数は呼び出されませんでした。親のメソッドで何度stateが変更されても子にとっては最初と最後の値だけみて「1回の変更」とみなされるようです。

投稿2018/11/27 15:45

karamarimo

総合スコア2551

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

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

panamax

2018/11/28 09:21

lastEl の値が変更された回数だけ computed プロパティが計算し直されて欲しい理由は、lastElにlastEl1~3の値("1"~"16"のいずれか)が代入されたことを検知するたびに、その値ごとに、指定した処理が行われて欲しかったからです。 watchオプションでも「1回の変更」とみなされてしまうということで、設計のアプローチを変えてやっていく事にしました。 最初に私が設計を考えていたときは、lastElという1つのdataの状態をみて処理を行う、というのが楽に思えたのですが、その操作を実現する方法が見つからなかったということは(恐らく実現する方法が完全にないわけではないと思いますが)、そもそもあまり好ましいやり方ではないのかもしれないと思うに至りました。 色々と勉強になりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問