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

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

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

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

1回答

4042閲覧

非同期処理にて取得した結果をVueの子コンポーネントに渡したい

cimatp0j

総合スコア10

Vue.js

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

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

0クリップ

投稿2022/03/10 08:08

編集2022/03/10 08:23

Vue3のCompositionAPIにて、親コンポーネント内の非同期で処理した結果を子コンポーネントに渡そうとしているのですが期待した結果にならないため質問いたします。

前提

テストコードのようにpathsとdataというプロパティを持ったオブジェクトをstatという名前で子コンポーネントに渡そうとしています。
※実際は渡したいプロパティが多いためオブジェクトとしてまとめて渡したい。
※Vuexを導入するほどの規模ではないのでなるべくプラグインを使わずに解決したい。
※allSettledでrejectされるとリクエストurlの情報が失われるためpathsとdataセットで渡したい。

環境

  • vue: ^3.2.13
  • ブラウザ:FirefoxおよびGoogleChromeにて確認

想定する動作

mount時もしくはボタンクリック時にfetchAPIを複数実行し、得られた結果をdataプロパティに格納する。getStatusが終了した時点でdataには結果が入っているので、stat.valueにはpathsとdataを持ったオブジェクトが代入されるはずである。

実際の動作

stat.valueをコンソール出力するとdataプロパティを確認できるが、その後にstat.value.pathsとstat.value.dataを出力すると前者のみ存在し、後者はundefinedと出力される。子コンポーネントで変更検知したタイミングでも同様の状態のまま渡っている。

質問したいこと

  1. Promise.allSettled().then()が終了した時点ですべてのPromiseは解決されているという認識でいいでしょうか。
  2. pathsが取得できてdataが取得できないということは非同期処理の結果が格納されていないと推察しますが、getStatusメソッドは非同期処理の完了を待たずに終了しているのでしょうか。
  3. dataに結果が格納されてから子コンポーネントにオブジェクトを渡すにはどういった方法をとる必要があるでしょうか。

テストコード

・Parent.vue

js

1<template> 2 <h3>Parent</h3> 3 <button @click="execute">取得</button> 4 <Child :stat="stat" /> 5 <div>{{ stat }}</div> 6</template> 7 8<script setup> 9import { ref, onMounted } from 'vue'; 10import Child from '@/components/Child.vue'; 11 12const stat = ref({}) //オブジェクトごと代入する想定でrefとしている 13 14onMounted(() => { 15 execute() 16}); 17 18const execute = () => { 19 const urls = [ 20 'https://httpbin.org/status/200', // "OK" 21 'https://httpbin.org/status/404', // "NG" 22 ]; 23 // 取得した結果をオブジェクトとしてstatに格納。 24 stat.value = getStatus(urls); 25 console.log('parent') 26 console.log(stat.value) // consoleではdata,paths共に結果が格納されている 27 // data: Array [ "OK", "NG" ] 28 // paths: Array [ "https://httpbin.org/status/200", "https://httpbin.org/status/404" ] 29 console.log(stat.value.paths) // Array [ "https://httpbin.org/status/200", "https://httpbin.org/status/404" ] 30 console.log(stat.value.data) // undefined 31 console.log('parent-end') 32} 33 34const getStatus = (urls) => { 35 const results = {}; 36 results['paths'] = urls; 37 const promises = urls.map(url => fetch(url)); 38 // ここで全てのPromiseを解決した値がほしい 39 Promise.allSettled(promises).then(resp => { 40 results['data'] = resp.map(r => { 41 console.log(r) 42 if (r.status === "fulfilled"){ 43 if(r.value.ok){ 44 return 'OK'; 45 } else { 46 return 'NG'; 47 } 48 } else { 49 return 'ERROR'; 50 } 51 }); 52 }); 53 return results; 54} 55</script>

・Child.vue

js

1<template> 2 <h4>Child</h4> 3 <div v-for="(path, i) in paths" :key="i"> 4 <div>{{ path }}:{{ data[i] }}</div> 5 </div> 6</template> 7 8<script setup> 9import { ref, toRef, watch } from 'vue'; 10 11const props = defineProps({ //eslint-disable-line 12 stat: { 13 type: Object, 14 required: true, 15 default: () => ({ 16 paths: [], 17 data: [], 18 }) 19 } 20}); 21 22const stat = toRef(props, 'stat'); 23const paths = ref([]); 24const data = ref([]); 25 26watch(props, () => { 27 console.log('child') 28 console.log(props.stat) // ->consoleではdata,paths共に結果が格納されている 29 // data: Array [ "OK", "NG" ] 30 // paths: Array [ "https://httpbin.org/status/200", "https://httpbin.org/status/404" ] 31 paths.value = stat.value.paths 32 data.value = stat.value.data 33 console.log(props.stat.paths) // ->Array [ "https://httpbin.org/status/200", "https://httpbin.org/status/404" ] 34 console.log(paths.value) // ->Array [ "https://httpbin.org/status/200", "https://httpbin.org/status/404" ] 35 console.log(props.stat.data) // ->undefined 36 console.log(data.value) // ->undefined 37 console.log('child-end') 38}) 39</script> 40

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

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

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

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

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

guest

回答1

0

自己解決

最終的にasync/await構文を使用して下部のようなコードで目的の動作を実現できました。
いろいろ検証し、thenはコールバックを登録するだけなのでPromiseの解決を待たずに次へ進むが、awaitはPromiseの解決を待つということを理解できました。
同期的なイメージを持って記述する場合はawaitを使っておくのが安全そうです。

・改善したParent.js(今回の場合はonMountedのasync/awaitはなくても支障ない)

js

1<template> 2 <h3>Parent</h3> 3 <button @click="execute">取得</button> 4 <Child :stat="stat" /> 5 <div>{{ stat }}</div> 6</template> 7 8<script setup> 9import { ref, onMounted } from 'vue'; 10import Child from '@/components/Child.vue'; 11 12const stat = ref({}); //オブジェクトごと代入する想定でrefとしている 13 14onMounted(async () => { 15 await execute() 16}); 17 18const execute = async () => { 19 const urls = [ 20 'https://httpbin.org/status/200', // "OK" 21 'https://httpbin.org/status/404', // "NG" 22 ]; 23 // 取得した結果をオブジェクトとしてstatに格納。 24 stat.value = await getStatus(urls) 25 26 console.log('parent') 27 console.log(stat.value) 28 console.log(stat.value.paths) 29 console.log(stat.value.data) 30 console.log('parent-end') 31} 32 33const getStatus = async (urls) => { 34 const results = {}; 35 results['paths'] = urls; 36 const promises = urls.map(url => fetch(url)); 37 // ここで全てのPromiseを解決した値がほしい 38 const resp = await Promise.allSettled(promises) 39 results['data'] = resp.map(r => { 40 console.log(r) 41 if (r.status === "fulfilled"){ 42 if(r.value.ok){ 43 return 'OK'; 44 } else { 45 return 'NG'; 46 } 47 } else { 48 return 'ERROR'; 49 } 50 }); 51 return results; 52} 53</script> 54

投稿2022/03/11 03:13

cimatp0j

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問