📑

ユーザー詳細、ファイル詳細でクリックが早いと、storeの前のデータが表示されてしまう

2021/11/21に公開

原因調査

ハマった
apiを通信する処理のコードは、全て非同期にしているため、原因が不明な状態
4、5あたりが怪しいと踏んでいて、4の時点で、本来なら対象の音声ファイルを押下すれば、そのファイルの配列のインデックスが取得できる想定なのですが、できていなそう
非同期と関係なさそうと踏んでいる。(最初のトップページでのデータが問題なく格納できているため)
トップページの表示
1

pages/TopAfterLogin.vue
  asyncData: async function(context) {
      // すべての音声ファイルを取得する
    await context.store.dispatch('musicFiles/musicFileTopPageData')
  },

2
store/musicFiles.js

  musicFileTopPageData(context) {
    let items = []
    this.$axios.$get('api/musicFileData')
      .then(response => {
        items = response
        console.log(items)
        context.commit('setmusicFileTopPageData', items)
      })
      .catch(error => {
        console.log(error)
      })
  },

3(ここでstoreに格納)

store/musicFiles.js
  setmusicFileTopPageData (state, items) {
    state.items = items
    console.log(items)
  },

トップから詳細への遷移
4

pages/TopAfterLogin.vue
<div class="content" v-for="(item, index) in $store.getters['musicFiles/items'].items" :key="index" @click="setMusicFileData(item.title, item.cover_image, item.music_file, item.user_name, item.user_id, item.id, item.description, item.user_icon)">
pages/TopAfterLogin.vue
    setMusicFileData (clickedFileTitle, clickedFileCoverImage, clickedFileMusicfile, clickedFileUserName, clickedFileUserId, clickedFileId, clickedFileUserDescription, clickedFileUserUserIcon) {
      this.clickedFileTitle = clickedFileTitle
      this.clickedFileCoverImage = clickedFileCoverImage
      this.clickedFileMusicfile = clickedFileMusicfile
      this.clickedFileUserName = clickedFileUserName
      this.clickedFileUserId = clickedFileUserId
      this.clickedFileId = clickedFileId
      this.clickedFileUserDescription = clickedFileUserDescription
      this.clickedFileUserUserIcon = clickedFileUserUserIcon
      console.log(clickedFileUserDescription)
      console.log(clickedFileUserUserIcon)
      this.$store.dispatch('musicFiles/setMusicFileData', {
        clickedFileTitle: this.clickedFileTitle,
        clickedFileCoverImage: this.clickedFileCoverImage,
        clickedFileMusicfile: this.clickedFileMusicfile,
        clickedFileUserName: this.clickedFileUserName,
        clickedFileUserDescription: this.clickedFileUserDescription,
        clickedFileUserUserIcon: this.clickedFileUserUserIcon,
        // フォローで渡すためのやつ
        clickedFileUserId: this.clickedFileUserId,
        clickedFileId: this.clickedFileId,
      })
    },

5(ここで既に前に表示したデータのidが入っている)

store/musicFiles.js

  setMusicFileData(context, payload) {
    const musicFiledatum = {
      clickedFileTitle: payload.clickedFileTitle,
      clickedFileCoverImage: payload.clickedFileCoverImage,
      clickedFileMusicfile: payload.clickedFileMusicfile,
      clickedFileUserName: payload.clickedFileUserName,
      clickedFileUserId: payload.clickedFileUserId, //storeへ格納→詳細ページでのasyckdataでのapi取得に使用したい
      clickedFileId: payload.clickedFileId, //storeへ格納→詳細ページでのasyckdataでのapi取得に使用したい
      clickedFileUserDescription: payload.clickedFileUserDescription,
      clickedFileUserUserIcon: payload.clickedFileUserUserIcon,
    }
    const musicFileData = [];
    musicFileData.push(musicFiledatum)
    context.commit('setMusicFileDataMutations', musicFileData)
  },

6(ここで既に前に表示したデータのidがstoreに格納)
store/musicFiles.js

  setMusicFileDataMutations(state, musicFileData) {
    // console.log(musicFileData)
    // console.log(state.musicFileData)
    state.musicFileData = musicFileData
  },

ファイル詳細画面での表示〜
7(既に前に表示したデータのapiのurlに格納されるパラメータとなってしまう)
pages/_user/_title.vue

    asyncData: async function(context) {
        context.store.commit("loading/setLoading", true)
        let clickedFileUserId = ''
        // 配列でclickedFileUserId取得
        context.store.getters['musicFiles/musicFileData'].forEach(musicFiledatum => {
            clickedFileUserId = musicFiledatum.clickedFileUserId
        });
        console.log(clickedFileUserId)
        let clickedFileId = ''
        context.store.getters['musicFiles/musicFileData'].forEach(musicFiledatum => {
            clickedFileId = musicFiledatum.clickedFileId
        });
        console.log(clickedFileId)
        await context.store.dispatch('musicFiles/musicDetailPageData', {
            clickedLoginUserId: context.store.state.auth.user.id,
            clickedFileId: clickedFileId,
            clickedFileUserId: clickedFileUserId,
        })
        context.store.commit("loading/setLoading", false)
    },

解決

ライフサイクルフックを理解してないことにより、ハマる
asyncDataを使用していた
データをストアに入れてから表示させるため、fetchを使用する

fetchでapi通信する
ユーザー詳細
pages/_user/index.vue

    // データをストアに入れてから表示させるため、fetchを使用する
    // topページからデータをストアに格納→"そのデータを元に詳細データを取得・storeに格納→storeのデータを表示する"の流れ
    fetch: async function() {
        this.$store.commit("loading/setLoading", true)
        let clickedFileUserId = ''
        // 配列でclickedFileUserId取得
        this.$store.getters['musicFiles/musicFileData'].forEach(musicFiledatum => {
            clickedFileUserId = musicFiledatum.clickedFileUserId
        });
        await this.$store.dispatch('musicFiles/userDetailPageData', {
            clickedFileUserId: clickedFileUserId,
        })
        this.$store.commit("loading/setLoading", false)
        this.followedId = this.$store.getters['musicFiles/followedId']
        this.userDetailItems = this.$store.getters['musicFiles/userDetailItems']
    },

ファイル詳細
pages/_user/_title.vue

    // データをストアに入れてから表示させるため、fetchを使用する
    // topページからデータをストアに格納→"そのデータを元に詳細データを取得・storeに格納→storeのデータを表示する"の流れ
    fetch: async function() {
        this.$store.commit("loading/setLoading", true)
        let clickedFileUserId = ''
        // 配列でclickedFileUserId取得
        this.$store.getters['musicFiles/musicFileData'].forEach(musicFiledatum => {
            clickedFileUserId = musicFiledatum.clickedFileUserId
        });
        let clickedFileId = ''
        this.$store.getters['musicFiles/musicFileData'].forEach(musicFiledatum => {
            clickedFileId = musicFiledatum.clickedFileId
        });
        await this.$store.dispatch('musicFiles/musicDetailPageData', {
            clickedLoginUserId: this.$store.state.auth.user.id,
            clickedFileId: clickedFileId,
            clickedFileUserId: clickedFileUserId,
        })
        this.$store.commit("loading/setLoading", false)
        this.followedId = this.$store.getters['musicFiles/followedId']
        this.userId = this.$store.getters['musicFiles/userId']
        this.commentInfos = this.$store.getters['musicFiles/commentInfos']
    },

おまけ

createdでも行けそうだが

created

Vueインスタンスが初期化されたあと、データも初期化されたときに呼ばれる
dataへのデータ挿入等に使用する

参考

https://qiita.com/kj455/items/451481e4551cf33d1f19
https://takabeeblog.com/nuxtjs-lifecyclehook/
https://designsupply-web.com/media/programming/6849/
https://qiita.com/kj455/items/451481e4551cf33d1f19

Discussion