Programing

vuex의 "모사" 돌연변이

c10106 2022. 4. 12. 20:47
반응형

vuex의 "모사" 돌연변이

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()호출 실패, 저장소에 있는 로컬 설정과 원격 설정이 동기화되지 않음.내가 이 행동에서 꼭 이루고 싶은 것은 다음과 같은 것이다.

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

나는 실제로 저지르지 않고 새로운 주를 얻고 싶다.원격 호출이 성공하면 실제로 스토어를 업데이트하겠다.그렇지 않으면 그대로 있을 것이다.

(변이함수의 논리를 실제로 복제하지 않고) 이것을 달성하는 가장 좋은 방법은 무엇일까?어쩌면 "undo"?잘 모르겠어.

이렇게 하는 한 가지 방법은 다음과 같다: (실수를 바로잡은 @Bert의 신용)

  1. 다음을 사용하여 이전 상태 저장const oldState = state;돌연변이를 일으키기 전에 말이야

  2. 비동기 호출을 다음으로 줄임try-catch막다

  3. 만약remoteSettings실패하면 에 처형을 넘길 것이다.catch막다

  4. 캐치 블록에서 돌연변이를 일으켜 상태를 재설정한다.

예:

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)
      }
    }

  }
};

@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>

참조URL: https://stackoverflow.com/questions/47737612/simulate-mutations-in-vuex

반응형