2017-12-10 15 views
1
import { remoteSettings } from 'somewhere'; 

const store = { 
    state: { 
     view: { 
      foo: true 
     } 
    }, 
    mutations: { 
     toggleFoo(state) { 
      state.view.foo = !state.view.foo; 
     } 
    }, 
    actions: { 
     async toggleFoo({ state, commit }) { 
      commit('toggleFoo'); 
      await remoteSettings.save(state); 
     } 
    } 
}; 

私はこれのようなシンプルな店を持っていると言います。 toggleFooアクションは突然変異を適用し、非同期呼び出しを行うことによって新しい状態を保存します。ただし、remoteSettings.save()呼び出しが失敗した場合、ストア内のローカル設定とリモート設定が同期していません。このアクションで本当に達成したいことは、次のようなものです:vuexの "Simulate"変異

async toggleFoo({ state, commit }) { 
    const newState = simulateCommit('toggleFoo'); 
    await remoteSettings.save(newState); 
    commit('toggleFoo'); 
} 

私は実際にそれをコミットせずに新しい状態を取得したいと思います。リモート呼び出しが成功すると、実際にストアを更新します。もしそうでなければ、それはそのままの状態にとどまるでしょう。

これを達成する最も良い方法は何ですか(実際には突然変異関数のロジックを複製する必要はありません)。 「元に戻す」とか?よく分かりません。これを行うための

答えて

2

@VamsiKrishnaからの借入コード(ありがとう)、私は代替案を提案します。私の意見では、サーバーに変更を送信し、成功するとローカルの状態を更新したいとします。ここに実例があります。

ロジックが重複しないように、変更を関数に抽象化します。

console.clear() 
 

 
const remoteSettings = { 
 
    save(state){ 
 
    return new Promise((resolve, reject) => setTimeout(() => reject("Server rejected the update!"), 1000)) 
 
    } 
 
} 
 

 
function updateFoo(state){ 
 
    state.view.foo = !state.view.foo 
 
} 
 

 
const store = new Vuex.Store({ 
 
    state: { 
 
    view: { 
 
     foo: true 
 
    } 
 
    }, 
 
    mutations: { 
 
    toggleFoo(state) { 
 
     updateFoo(state) 
 
    }, 
 
    }, 
 
    actions: { 
 
    async toggleFoo({ state, commit }) { 
 
     // Make a copy of the state. This simply uses JSON stringify/parse 
 
     // but any technique/library for deep copy will do. Honestly, I don't 
 
     // think you would be sending the *entire* state, but rather only 
 
     // what you want to change 
 
     const oldState = JSON.parse(JSON.stringify(state)) 
 
     // update the copy 
 
     updateFoo(oldState) 
 
     try { 
 
     // Attempt to save 
 
     await remoteSettings.save(oldState); 
 
     // Only commit locally if the server OKs the change 
 
     commit('toggleFoo'); 
 
     } catch(err) { 
 
     // Otherwise, notify the user the change wasn't allowed 
 
     console.log("Notify the user in some way that the update failed", err) 
 
     } 
 
    } 
 
    } 
 
}) 
 

 
new Vue({ 
 
    el: "#app", 
 
    store, 
 
    computed:{ 
 
    foo(){ 
 
     return this.$store.state.view.foo 
 
    } 
 
    }, 
 
    mounted(){ 
 
    setTimeout(() => this.$store.dispatch("toggleFoo"), 1000) 
 
    } 
 
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script> 
 
<div id="app"> 
 
    <h4>This value never changes, because the server rejects the change</h4> 
 
    {{foo}} 
 
</div>

+0

ありがとうございます。私は今のところこのようなものを持っています。これは、変更を適用してからそれらを元に戻すのではなく、うまくいくように見えます。 vuexでこのような場合に推奨される方法/ベストプラクティス/省略表現があるかどうかは疑いがありませんでした。 – mkubilayk

4

一つの方法は、次のようになります。(訂正ミスのため @Bert にクレジット)

  1. ストア突然変異をコミットする前にconst oldState = state;を使用して、古い状態。

  2. try-catchブロックで非同期コールをラップします。

  3. remoteSettingsが失敗すると、実行はcatchブロックに渡されます。

  4. catchブロックで、状態をリセットするために突然変異をコミットします。

例:

const store = { 
    state: { 
    view: { 
     foo: true 
    } 
    }, 
    mutations: { 
    toggleFoo(state) { 
     state.view.foo = !state.view.foo; 
    }, 
    resetState(state, oldState){ 
     //state = oldState; do not do this 

     //use store's instance method replaceState method to replace rootState 
     //see : https://vuex.vuejs.org/en/api.html 
     this.replaceState(oldState) 
    } 
    }, 
    actions: { 
    async toggleFoo({ state, commit }) { 
     const oldState = JSON.parse(JSON.stringify(state)); //making a deep copy of the state object 
     commit('toggleFoo'); 
     try { 
     await remoteSettings.save(newState); 
     //commit('toggleFoo'); no need to call this since mutation already commited 
     } catch(err) { 
     //remoteSettings failed 
     commit('resetState', oldState) 
     } 
    } 

    } 
}; 
+0

これは少し後方の典型的な流れからです。非同期呼び出しを行い、成功するとコミットします。そうすれば、別の状態に戻す必要はありません(これはUIで奇妙な動作を引き起こす可能性があります)。 – Bert

+0

@Bert yup、これは後方ですが、非同期呼び出しで突然変異状態を送信したかったので、非同期呼び出しの前に突然変異をコミットしました。 –

+0

その後、状態のコピーを送信して更新する必要があります。これは実際には機能しません。 'oldState = state'を設定すると、参照によってコピーが作成され、元に戻すときには、自分自身と同じ状態に設定するだけです。 https://codepen.io/Kradek/pen/wPVVyO?editors=1010 – Bert

関連する問題