私は最近jQからVueJSであるより構造化されたフレームワークに物事を移行し始めました、そして私はそれが大好きです!
概念的には、Vuexは私にとってちょっとしたパラダイムシフトでしたが、私はそのすべてが今何をしているのか知っていて、それを完全に手に入れたと確信しています!しかし、主に実装の観点から、いくつかの小さなグレーの領域があります。
これは設計上は問題ないと思いますが、単方向データフローのVuex cycle と矛盾するかどうかはわかりません。
基本的に、アクションからpromise(like)オブジェクトを返すことは良い習慣と考えられますか?私はこれらを失敗の状態などを持つ非同期ラッパーとして扱うので、約束を返すのに適しているように思えます。反対にミューテーターは物事を変えるだけで、store/module内の純粋な構造です。
Vuexのactions
は非同期です。呼び出し元の関数(アクションの開始者)にアクションが完了したことを知らせる唯一の方法は、Promiseを返して後で解決することです。
例を示します。myAction
はPromise
を返し、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")
})
}
}
上記のとおり、actions
がPromise
を返すことは非常に有益です。そうでなければ、アクションイニシエータが何が起こっているのか、そしてユーザインタフェースに何かを表示するのに十分安定しているときを知る方法はありません。
そしてmutators
に関する最後のメモ - あなたが正しく指摘したように、それらは同期的です。これらはstate
の内容を変更し、通常はactions
から呼び出されます。 Promises
がその部分を処理するので、mutators
とactions
を混在させる必要はありません。
編集:単方向データフローのVuexサイクルに関する私の見解:
コンポーネント内のthis.$store.state["your data key"]
のようなデータにアクセスする場合、データフローは単方向です。
アクションからの約束は、アクションが完了したことをコンポーネントに知らせることだけです。
コンポーネントは、上記の例のpromise resolve関数からデータを取得するか(単方向ではないため、推奨されません)、または単方向でvuexデータライフサイクルに従う$store.state["your data key"]
から直接取得することができます。
上記の段落では、あなたのアクションでhttp呼び出しが完了すると、あなたのミューテーターがVue.set(state, "your data key", http_data)
を使うと仮定しています。
閉ざされたトピックに関する情報のためだけに、約束を作成する必要はありません、axiosはそれ自体を返します:
例:
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
})
})
};
アクション
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...
}
})
TL:DR;必要なときだけあなたからの約束を返すが、DRYは同じ行動を連鎖する。
私は長い間、アクションを返すことは一方向のデータフローのVuexサイクルと矛盾しています。
しかし、あなたの行動から約束を返すことが「必要」かもしれないEdge CASESがあります。
アクションが2つの異なるコンポーネントからトリガーされ、それぞれが失敗のケースを異なる方法で処理できる状況を想像してください。その場合は、ストアに異なるフラグを設定するためのパラメータとして呼び出し側コンポーネントを渡す必要があります。
ダムの例
ユーザーがnavbarおよび/ profileページ(navbarを含む)でユーザー名を編集できるページ。どちらも「ユーザー名の変更」アクションをトリガーしますが、これは非同期です。約束が失敗した場合、ページにはユーザーがユーザー名を変更しようとしていたコンポーネントのエラーのみが表示されます。
もちろんこれは愚かな例ですが、コードを重複させずに2つの異なるアクションで同じ呼び出しを行わずにこの問題を解決する方法はわかりません。