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

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

詳細はこちら
Vue.js

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

Q&A

解決済

1回答

8370閲覧

【Vue】axiosで実行する複数の処理を順番に実行する

hasshy

総合スコア102

Vue.js

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

0グッド

1クリップ

投稿2019/10/16 10:10

axiosを使ってAPI経由でデータのやり取りをするアプリケーションを作っています。
組み合わせるて順番に実行させる方法についてご教示ください。

概要

下記のようなフォームでTodoを登録し、
登録したものも含めて一覧で表示するとします。

イメージ説明

API経由でデータを保存して、保存したデータを含めて表示用に加工された一覧データを取得して更新します。
その場合、APIにリクエストするのは下記の2つを順番に処理します。

  1. データベースにデータを追加
  2. データ一覧を更新

実現したい事

API経由で通信中は別の処理ができないようにしたいです。
上記フォームの「送信」ボタンを連続で押されても処理が終わるまでは何もしないようにしたいです。

ソース

下記のようなコンポーネントを用意しました。
多重送信できないように、processingフラグで管理しています。

APIとのやりとりを行う関数は次のような物を用意しました。
上記フォームとは別に管理画面が用意しておりTodoを操作できる想定です。
そのため、登録時に最新情報を取得する必要があります

関数名内容URLメソッド
addTodo()投稿文(body)をDBに追加http://api.example.com/api/todosPOST
getTodos()保存された内容をDBから取得http://api.example.com/api/todosGET

js

1<template> 2<div> 3 <div class="form-group row justify-content-center"> 4 <input 5 class="form-control col-sm-10" 6 type="text" 7 name="body" 8 :disabled="processing" 9 /> 10 <button 11 class="btn btn-primary2 col-sm-2" 12 type="button" 13 @click="addTodo" 14 >送信する</button> 15 </div> 16 17 <div class="row justify-content-center"> 18 <div class="col-11"> 19 <div class="table-responsive"> 20 <table class="table"> 21 <thead> 22 <tr> 23 <th class="th-time">時間</th> 24 <th class="th-name">内容</th> 25 </tr> 26 </thead> 27 <tbody> 28 <tr v-for="todo in todos"> 29 <td>{{ todo.created_at }}</td> 30 <td>{{ todo.text }}</td> 31 </tr> 32 </tbody> 33 </table> 34 </div> 35 </div> 36 </div> 37</div> 38</template> 39 40<script> 41export default { 42 name: "TodoComponent", 43 props: { 44 disabled: { 45 type: Boolean, 46 default: false 47 } 48 }, 49 data () { 50 return { 51 body: '', 52 todos: [], 53 processing: false 54 } 55 }, 56 methods: { 57 // todo追加 58 addTodo() { 59 // プロセスが終了していない場合は何もしない 60 if(this.processing) { 61 return false; 62 } 63 // プロセスを始める 64 this.processing = true; 65 66 let self = this; 67 let data = { 68 body: this.body 69 }; 70 71 let url = 'http://api.example.com/api/todos'; 72 axios.post(url, data) 73 .then(function(){ 74 // 実現したい事の2.に書いた一覧の取得 75 // ただし、非同期ではないためこの処理を待たずにfinallyに進んでしまう 76 self.getTodos() 77 }) 78 .catch(function(e){ 79 // 登録できなかった時はエラー 80 console.log('error'); 81 }) 82 .finally(function() { 83 // 登録できてもできなくてもプロセスの状態を元に戻す 84 self.processing = false; 85 }); 86 }, 87 88 // 一覧取得 89 getTodos() { 90 let self = this; 91 let url = 'http://api.example.com/api/todos'; 92 93 axios.get(url, { 94 headers: { 95 "Content-Type": "application/json" 96 }, 97 data: {} 98 }) 99 .then(function(result){ 100 // 一覧を更新 101 self.todos = result.data.todos; 102 }) 103 .catch(function (e) { 104 console.error(e); 105 }) 106 }, 107 } 108 mounted() { 109 // 読み込み時に最新の一覧を取得しておく 110 this.getTodos(); 111 }, 112} 113</script> 114

現状

1の登録時は制止できるのですが、2の一覧取得する処理のgetTodos()中に実行できてしまいます。
登録処理のaddTodoのthenの中に書いているので、追加中かどうかは判定できているのですが、getTodos()の状態は取得することが出来ていません。

axiosの処理の後に、再度axiosを入れ子にする方法はないでしょうか?

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

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

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

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

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

guest

回答1

0

ベストアンサー

◯ 概要

Promise を止めるには await が使えます。自信はないのですが、これを利用してはどうでしょうか?

◯ 挙動

sleep を Promise 化したもので挙動を確認してみます。

javascript

1async function sampleCode() { 2 await sleep(3) 3 .then(() => { 4 console.log("No. 1"); 5 }) 6 .catch(error => { 7 console.log(error); 8 }); 9 10 console.log("No. 2"); 11} 12 13function sleep(time) { 14 return new Promise(resolve => { 15 setTimeout(() => { 16 resolve(); 17 }, time * 1000); 18 }); 19} 20 21sampleCode();
> sampleCode(); No. 1 No. 2 > // ちなみに await を消すと No. 2, No. 1 で表示されます。

◯ 提案

methods: { addTodo: async () => { // <--- 追記 if(this.processing) { return false; } this.processing = true; let self = this; let data = { body: this.body }; let url = 'http://api.example.com/api/todos'; axios.post(url, data) .then(function(){ await self.getTodos() // <--- 追記 }) .catch(function(e){ console.log('error'); }) .finally(function() { self.processing = false; }); }, // 一覧取得 getTodos: async () => { // <--- 追記 let self = this; let url = 'http://api.example.com/api/todos'; return axios.get(url, { // <--- 追記 headers: { "Content-Type": "application/json" }, data: {} }) .then(function(result){ // 一覧を更新 self.todos = result.data.todos; }) .catch(function (e) { console.error(e); }) }, }

◯ そのほか

async/await を使わなくても、止められないか MDN を見て allSettled というのを見つけたのですが。そういった動きはしてくれませんでした。

投稿2019/10/16 17:12

編集2019/10/16 17:16
nico25

総合スコア830

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

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

hasshy

2019/10/17 02:48

お忙しい中調べていただきありがとうございます。 回答を確認させていただきました。 async/awaitを使って応答を待つ事も出来るのですね。 実装例まで書いていただきとても助かります。 参考にさせていただきます。
hasshy

2019/10/17 14:41

ありがとうございます。 解決できました。 一点修正が必要な箇所がありましたのでご共有させてください。 axiosのthenで使用する無名関数は、async関数にする必要がありました。
nico25

2019/10/17 15:18

コードが不正確で、お手数おかけしました。 ご共有いただき、ありがとうございます。 勉強になりました :)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問