【Vue.js】登録処理後、検索結果を維持した一覧画面に遷移し、かつ「登録完了」のトーストを表示させ・・・

###それを共通化する
というお話です。
#いきさつ
現在仕事でVue.jsを書いており、上記のことを頼まれ実装したので備忘録として。

#使用しているライブラリ
・Vuex
・Vue Router
・BootstrapVue

#流れ
こんな感じです。
・子コンポーネント(Main.vue)はウォッチャで前画面の情報をstoreに保持させている。
・孫コンポーネント(Form.vue)で登録ボタン押下、登録処理後にmixinsで呼び出したメソッドで一覧画面へ。
・親コンポーネント(app.vue)がクエリに`toast_type`があることを検知すると、トーストを表示させる。
・`toast_type`がクエリにない一覧画面に遷移する。

![スクリーンショット 2020-03-04 2.13.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358229/d79139c6-733c-1445-a595-220499d34bcf.png)


今書いてて思いますが、絶対もっと良い方法があると思う・・・。

#ソース

####子コンポーネント
Main.vue

```js
  watch: {
    '$route': function (to, from) {
      // 前画面情報を取得
      this.$store.commit('from_page_param/setFromPage', {
        full_path: from.fullPath,
        name: from.name,
        path: from.path
      })
    }
  }
```

####store
from_page_param.js

```js

export default {
  namespaced: true,
  state: {
    from_page: {
      full_path: '',
      path: '',
      name: ''
    }
  },

  mutations: {
    setFromPage (state, data) {
      state.from_page.full_path = data.full_path;
      state.from_page.path = data.path;
      state.from_page.name = data.name;
    }
  },

  getters: {
    fromPage: state => {
      return state.from_page;
    }
  }
}
```
ここまでが前画面情報保持。

####孫コンポーネント
Form.vue
上部で`myMixin.vue`をインポートし、mixinsで定義しているものとしてください。

```js

      onClickSend () {
        this.$loading.load(this.$auth.api.patch(`/admin/hoges/create.json`, {
          hoge: this.hoge
        })
        .then(response => {
          this.transitionProcessed('created', 'IndexPageName');
        })
        .catch(error => {
          if(error.response.status == 422) {
            this.errors = error.response.data.errors;
          }else{
            this.$errorHandlers.ajax(error);
          }
        }))
      },
```
見るべきは`this.transitionProcessed('created', 'IndexPageName');`。
このメソッドはForm.vueでimportしてきた`myMixin.vue`に書かれたメソッドです。
第一引数にはクエリ、`toast_type`のvalue用、第二引数には遷移する一覧画面のNameを渡します。
この中身が・・・

####ミックスイン
myMixin.vue

```js
    // 登録処理後などの一覧画面遷移（検索結果保持用）
    transitionProcessed (toast_type, name) {
      let from_page = this.$store.getters['from_page_param/fromPage'];
      if(from_page.full_path && from_page.name === name) {
        this.$router.push({ path: from_page.full_path, query: { toast_type: toast_type } })
      }else{
        this.$router.push({ name: name, query: { toast_type: toast_type } })
      }
    },
```
前画面情報があり、戻りたい画面とこれから戻る画面が一致していれば
検索条件を保持して`toast_type`をクエリに追加した一覧画面に遷移します。


####親コンポーネント

```js
methods: {
    // クエリからtoast_typeを削除してreplace
    replaceDeletedToast (path) {
      let query = Object.assign({}, this.$route.query)
      delete query['toast_type']
      this.$router.replace({path: path, query: query})
    }
  },

  watch: {
    '$route': function (to, from) {
      if (!!this.$route.query.toast_type){
        if(this.$route.query.toast_type === 'updated') {
          this.$bvToast.toast("更新しました", {
            variant: 'success',
            title: '完了'
          });
        } else if(this.$route.query.toast_type === 'created') {
          this.$bvToast.toast("登録しました", {
            variant: 'success',
            title: '完了'
          });
        } else if(this.$route.query.toast_type === 'deleted') {
          this.$bvToast.toast("削除されました", {
            variant: 'success',
            title: '完了'
          });
        }
        this.replaceDeletedToast(to.path);
      }
    }
  }
```

`toast_type`の中身で表示させるトーストを判断。
トースト表示後のURLは`localhost/admin/hoges/?page=2&toast_type=created`と`toast_type`が邪魔なので
`this.replaceDeletedToast(to.path);`の中で消し、replace！

#結果
次からは非同期処理後に`this.transitionProcessed('created', 'IndexPageName');` 
だけ書けばOK

#ハマったところ
app.vueのこの部分。実は最初`replace`ではなく`push`を使用していた

```js
this.$router.replace({path: path, query: query})
```

この場合ひとつ前の履歴は`localhost/admin/hoges/?page=2&toast_type=created`のような`toast_type`を含むパスとなり、ブラウザバックをすると、再びapp.vueがトースト表示させ、クエリを消して$router.push ... を延々と繰り返してしまう。

だがreplaceを使うことによってその遷移を履歴に残さないようにすることができ、結果的にブラウザバックでForm.vueの画面に戻ることができた。
これについてはこちらの記事を参考にしました。
[JSでブラウザの履歴を操作する](https://qiita.com/bunty/items/ebe1f9a87696b116f175)


#あとがき
より良い方法をご存知の方がいらっしゃればコメントをくださると嬉しいです。
エンジニア歴１年記念日のQiita投稿でした。