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

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

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

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

Vue CLI

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

Q&A

2回答

2729閲覧

VueでLoading表示をしたいが、Loading処理が後続の処理に引っ張られる

benq

総合スコア5

Vue.js

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

Vue CLI

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

0グッド

0クリップ

投稿2019/08/19 14:30

前提・実現したいこと

実現機能
画面中のデータ移動ボタン・・・データ移動ボタンを押すとストア内のデータを書き換える
このストアデータは件数が多いため、データ移動ボタンを押した際は、Loading表示をする。

環境
・Vue CLI
・Windows

発生している問題・エラーメッセージ

発生している問題
期待値としては、2.1の処理をした直後に、画面上にLoding表示を行いたいが、描画がされない。

現状ボタン押下時の処理は以下の流れです。
コンポーネント→アクション→ミューテーションの処理順で処理されていると思っています。

【コンポーネント側】 1. ボタン押下 2. actionの処理を実施 2.1 loading表示コンポーネントを表示するフラグをtrue(実際に画面に描画するためのフラグ 以下のa.vue内のdataインスタンスに保持) 2.2 データ移動のアクションを呼ぶ 【アクション側】 3. action.js 3.1 mutationを呼びデータを書き換える。 【ミューテーション側】 4.データ変更 【コンポーネント側】 アクション側からのリターンをコンポーネントが受ける 5.loadingコンポーネントを有効にするフラグをfalse

該当のソースコード(参考)

mutationの処理は、store内のデータ移動のみのため省略いたしました。

a.vue

<button @click="allMove()"></button> ・ ・ ・ methods: { ...mapActions([ actionOfAllMove: STORE_KEY + '/actionOfAllMove' ]),   allMove(){ this.loading = true console.log('1') this.actionOfAllMove().then(_ => { console.log('3') this.loading = false }) }

action.js

const actionOfAllMove = async (context) { let mutationTypes = types.ALL_MOVE console.log('2') await context.commit(mutationTypes) }

試したこと

  1. ソースのa.vue内のallMove()アクションをthis.loading = trueのみにした場合、Loading表示された。
  2. console.logを利用し、処理順を確認 1→2→3の順で動作していることを確認
  3. loading=trueを 別ミューテーションに切って、action.js内のactionOfAllMove内で2回呼んだがLoading表示されない

教えていただきたい内容

・1つのアクション内で、Lodingフラグの即時反映(データの書き換え前に反映したい)

ちなみに、別の箇所で、axiosを使った通信処理をaction側から呼びcontext commitとしている箇所は正常にLoading表示が先に表示されているため、axios経由ではない ただのデータ移動の場合にcontext commitをした場合に発生していると思われる。

まだ、Vueをやり始めたばかりで未熟ですが、よろしくお願いいたします。
何でもいいので、コメントいただけると助かります。

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

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

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

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

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

guest

回答2

0

benqさん

上記返信の解決策ですが、以下になります。

methods: { allMove(){ this.loading = true // 非同期処理 setTimeout(() => { this.actionOfAllMove() this.loading = false }) } }

https://codepen.io/yuhigash/pen/PoYmBVo?editors=1010

cf. 非同期処理キュー: https://jp.vuejs.org/v2/guide/reactivity.html#%E9%9D%9E%E5%90%8C%E6%9C%9F%E6%9B%B4%E6%96%B0%E3%82%AD%E3%83%A5%E3%83%BC

投稿2019/08/29 23:00

編集2019/08/29 23:01
yuhigash

総合スコア327

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

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

0

まず、Vuexにおいて commit内の処理(ミューテーション内の処理)は常に同期処理です。
なのでcommitawaitをつけても意味はありません。

もしもミューテーション内で非同期処理を行っているのであれば、それはactionの方に切り出してください

参考リンク - ミューテーションは同期的でなければならない

そして、JavaScriptは特殊な場合を除いて常にシングルスレッドで動作します。シングルスレッドで動作するということは「同期的な」データの移動処理の間は、他にどんな処理も行うことができないということです。つまり、Vueがthis.loadingフラグの変更を検知してDOMを更新する処理も行うことができないということです。

非同期処理ではないデータの移動というのはあまり想像がつきませんが、もしメモリ上のデータをコピーするとかいうことであれば、ローディング画面を出すことを諦めるか、もしくは以下のようにnextTick()を使うことで、ローディング画面を出してからデータの移動を行うことができるかもしれません。

  async allMove(){ this.loading = true await this.$nextTick() // ここでDOMの更新が完了するまで待つ console.log('1') this.actionOfAllMove().then(_ => { console.log('3') this.loading = false }) }

投稿2019/08/20 11:07

編集2019/08/20 11:12
KuwabataK

総合スコア306

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

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

benq

2019/08/23 02:25

KuwabataK さん ご回答ありがとうございます。 await this.$nextTick()で実装してみましたが改善はできませんでした。 非同期処理ではないデータの移動=メモリ上のデータ移動 になります。 実際には、配列A と 配列Bのデータを画面上で付け替える処理になります。  このときは確定データではないためサーバ側へ投げていない状況です。 https://codeday.me/jp/qa/20190424/688589.html このような記事も見つけたのですが、setTimeout 使ってもできませんでした。 メモリ上のデータ移動の場合はloadingなど使わないのが一般的なんですかね~。 なかなか 難しいです 笑
KuwabataK

2019/08/23 03:36

そーですね〜。私もメモリ上のデータコピーにローディング入れたことはないですね。メモリ上のコピーなんて、どんなに遅くても100ms以内ぐらいには終わるので、ローディングなんて入れても意味ない事が多いです。ちなみにコピーにかかる時間って実際測られました?。あまりにも早すぎてローディング画面を認識できない可能性はないですか?
benq

2019/08/23 05:25

実際データ移動の際には移動元に移動したかどうかのフラグを立てたりしているので実装・仕様の見直しもありだと思っています。毎日モヤッとだったので何とかならないかなというのと似たような人いたらドヤ顔で解決してやろうと密かに企んでました 笑 一応、処理としては遅く2~3秒くらいで先に描画が終わっているということはないかと思います。 以下 ちょっと試した内容なんですが私の見解では loading描画に必要な情報が内部的に欠け落ちている(DOM関連)のではないかと思っています。 以下、3のタイミングの処理でloading=trueにした場合はうまく動作します。  async allMove(){ this.loading = true await this.$nextTick() console.log('1') this.actionOfAllMove().then(_ => { console.log('3') this.loading = true // ここをtrueにした結果 この3のタイミングでloading表示されます }) }
KuwabataK

2019/08/23 09:29

実際動かしたわけではないので、確実なことは言えないのですが、描画に必要な情報が内部的に欠け落ちている。というよりは、DOMの描画更新処理がメモリ上のデータコピー完了まで遅延されている。と言った方が正しいような気がします。JavaScriptはシングルスレッドで動くので、メモリ上のデータコピー実行中はローディング画面をレンダリングすることはどう頑張ってもできません。 なので、コピーをはじめる前にDOMのローディング画面レンダリングを完了されなきゃいけない → nextTick でコピー処理の開始を遅延させればいけるんじゃない? と言う発想でnextTickを入れてみたのですが、ダメなんですねえ
benq

2019/08/26 06:54

>DOMの描画更新処理がメモリ上のデータコピー完了まで遅延されている。と言った方が正しいような気がします。 仰るとおり動きをみるとそう思えます。 色々とご助言いただきありがとうございます。 何か進展あれば連絡させていただければと思います。 一旦はありがとうございました。
yuhigash

2019/08/28 03:14

横からすみません。 さっと拝読したのみですが、問題の原因特定のために以下のことを試していただけませんか? ``` ... this.actionOfAllMove().then(_ => { console.log('3') // コメントアウトする // this.loading = false }) ... ``` KuwabataKさんが仰られている「あまりにも早すぎてローディング画面を認識できない可能性」の検証ができればと考えています。 また、スレッド内で仰られている「処理としては遅く2~3秒くらいで先に描画が終わっている」ですが、コンソールログとして「2」と「3」が出力される間隔が2 ~ 3秒ということでしょうか?
benq

2019/08/28 04:12

yuhigashさん コメントありがとうございます。 さきほど、試しました。 結論  3のタイミング(メモリ上のデータ移動が終わった後)で、Loadingが表示されます。  もちろんtureのままなので、画面上にLoadingがでっぱなしという状態でございます。
yuhigash

2019/08/29 22:58 編集

benqさん 返信が遅くなりました。検証していただき、ありがとうございます。 結果から、「あまりにも早すぎてローディング画面を認識できない可能性」はないと思います。 原因は以下の2つです。 ・同期的な処理に時間がかかっている ・tickのタイミングが同期的な処理の後に行われている 解決策ですが、「this.actionOfAllMove()」を非同期処理として実行してみてください。 コードが書けないので別回答として投稿します。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問