web-dev-qa-db-ja.com

Vuexアクションから約束を返す

私は最近jQからVueJSであるより構造化されたフレームワークに物事を移行し始めました、そして私はそれが大好きです!

概念的には、Vuexは私にとってちょっとしたパラダイムシフトでしたが、私はそのすべてが今何をしているのか知っていて、それを完全に手に入れたと確信しています!しかし、主に実装の観点から、いくつかの小さなグレーの領域があります。

これは設計上は問題ないと思いますが、単方向データフローのVuex cycle と矛盾するかどうかはわかりません。

基本的に、アクションからpromise(like)オブジェクトを返すことは良い習慣と考えられますか?私はこれらを失敗の状態などを持つ非同期ラッパーとして扱うので、約束を返すのに適しているように思えます。反対にミューテーターは物事を変えるだけで、store/module内の純粋な構造です。

84
Daniel Park

Vuexのactionsは非同期です。呼び出し元の関数(アクションの開始者)にアクションが完了したことを知らせる唯一の方法は、Promiseを返して後で解決することです。

例を示します。myActionPromiseを返し、http呼び出しを行い、後でPromiseを解決または拒否します - すべて非同期です。

actions: {
    myAction(context, data) {
        return new Promise((resolve, reject) => {
            // Do something here... lets say, a http call using vue-resource
            this.$http("/api/something").then(response => {
                // http success, call the mutator and change something in state
                resolve(response);  // Let the calling function know that http is done. You may send some data back
            }, error => {
                // http failed, let the calling function know that action did not work out
                reject(error);
            })
        })
    }
}

これで、あなたのVueコンポーネントがmyActionを起動するとき、それはこのPromiseオブジェクトを取得し、それが成功したかどうかを知ることができます。 Vueコンポーネントのサンプルコードは次のとおりです。

export default {
    mounted: function() {
        // This component just got created. Lets fetch some data here using an action
        this.$store.dispatch("myAction").then(response => {
            console.log("Got some data, now lets show something in this component")
        }, error => {
            console.error("Got nothing from server. Prompt user to check internet connection and try again")
        })
    }
}

上記のとおり、actionsPromiseを返すことは非常に有益です。そうでなければ、アクションイニシエータが何が起こっているのか、そしてユーザインタフェースに何かを表示するのに十分安定しているときを知る方法はありません。

そしてmutatorsに関する最後のメモ - あなたが正しく指摘したように、それらは同期的です。これらはstateの内容を変更し、通常はactionsから呼び出されます。 Promisesがその部分を処理するので、mutatorsactionsを混在させる必要はありません。

編集:単方向データフローのVuexサイクルに関する私の見解:

コンポーネント内のthis.$store.state["your data key"]のようなデータにアクセスする場合、データフローは単方向です。

アクションからの約束は、アクションが完了したことをコンポーネントに知らせることだけです。

コンポーネントは、上記の例のpromise resolve関数からデータを取得するか(単方向ではないため、推奨されません)、または単方向でvuexデータライフサイクルに従う$store.state["your data key"]から直接取得することができます。

上記の段落では、あなたのアクションでhttp呼び出しが完了すると、あなたのミューテーターがVue.set(state, "your data key", http_data)を使うと仮定しています。

182
Mani

閉ざされたトピックに関する情報のためだけに、約束を作成する必要はありません、axiosはそれ自体を返します:

参照: https://forum.vuejs.org/t/how-to-resolve-a-promise-object-in-a-vuex-action-and-redirect-to-another-route/18254/ 4

例:

export const loginForm = ({commit},data) => {
        return axios.post('http://localhost:8000/api/login',data).then((response) => {
            console.log(response);
            commit('logUserIn',response.data.data);
        }).catch((error) => {
            commit('unAuthorisedUser',{
                error:error.response.data
            })
        })
};
19
Anoop.P.A

アクション

ADD_PRODUCT : (context,product) => {
  return Axios.post(uri, product).then((response) => {
    if (response.status === 'success') {  
      context.commit('SET_PRODUCT',response.data.data)
    }
    return response.data
  });
});

構成要素

this.$store.dispatch('ADD_PRODUCT',data).then((res) => {
  if (res.status === 'success') {
    // write your success actions here....
  } else {
     // write your error actions here...
  }
})
6

TL:DR;必要なときだけあなたからの約束を返すが、DRYは同じ行動を連鎖する。

私は長い間、アクションを返すことは一方向のデータフローのVuexサイクルと矛盾しています。

しかし、あなたの行動から約束を返すことが「必要」かもしれないEdge CASESがあります。

アクションが2つの異なるコンポーネントからトリガーされ、それぞれが失敗のケースを異なる方法で処理できる状況を想像してください。その場合は、ストアに異なるフラグを設定するためのパラメータとして呼び出し側コンポーネントを渡す必要があります。

ダムの例

ユーザーがnavbarおよび/ profileページ(navbarを含む)でユーザー名を編集できるページ。どちらも「ユーザー名の変更」アクションをトリガーしますが、これは非同期です。約束が失敗した場合、ページにはユーザーがユーザー名を変更しようとしていたコンポーネントのエラーのみが表示されます。

もちろんこれは愚かな例ですが、コードを重複させずに2つの異なるアクションで同じ呼び出しを行わずにこの問題を解決する方法はわかりません。

0
srmico