[promise] Vuex 작업에서 약속 반환

저는 최근에 jQ에서 VueJS 인보다 구조화 된 프레임 워크로 마이그레이션하기 시작했습니다.

개념적으로 Vuex는 저에게 약간의 패러다임 전환 이었지만 지금은 그 모든 것이 무엇인지 알고 있으며 완전히 이해합니다! 그러나 대부분 구현 관점에서 볼 때 약간의 회색 영역이 있습니다.

이것은 디자인 상 좋지만 단방향 데이터 흐름 의 Vuex 주기 와 모순되는지 모르겠습니다 .

기본적으로 액션에서 promise (유사) 객체를 반환하는 것이 좋은 방법으로 간주됩니까? 나는 이것을 실패 상태 등의 비동기 래퍼로 취급하므로 약속을 반환하기에 적합한 것처럼 보입니다. 반대로 뮤 테이터는 단지 사물을 변경하고 스토어 / 모듈 내의 순수한 구조입니다.



답변

actionsVuex에서는 비동기식입니다. 호출 함수 (동작 개시 자)가 동작이 완료되었음을 알 수 있도록하는 유일한 방법은 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는 AS, actions그 부분 핸들.

편집 : 단방향 데이터 흐름의 Vuex주기에 대한 내 견해 :

this.$store.state["your data key"]구성 요소에서 와 같이 데이터에 액세스하는 경우 데이터 흐름은 단방향입니다.

작업의 약속은 구성 요소에 작업이 완료되었음을 알리는 것입니다.

구성 요소는 위 예제의 약속 해결 기능에서 데이터를 가져 오거나 ( $store.state["your data key"]단방향이 아니므로 권장하지 않음) 직접 단방향이고 vuex 데이터 수명주기를 따릅니다.

위의 단락은 Vue.set(state, "your data key", http_data)http 호출이 작업에서 완료되면 mutator가를 사용한다고 가정합니다 .


답변

닫힌 주제에 대한 정보를 위해 :
약속을 만들 필요가 없습니다. 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) => {
          commit('logUserIn', response.data);
        })
        .catch((error) => {
          commit('unAuthorisedUser', { error:error.response.data });
        })
    }

다른 예시:

    addEmployee({ commit, state }) {
      return insertEmployee(state.employee)
        .then(result => {
          commit('setEmployee', result.data);
          return result.data; // resolve
        })
        .catch(err => {
          throw err.response.data; // reject
        })
    }

async-await 를 사용한 또 다른 예

    async getUser({ commit }) {
        try {
            const currentUser = await axios.get('/user/current')
            commit('setUser', currentUser)
            return currentUser
        } catch (err) {
            commit('setUser', null)
            throw 'Unable to fetch current user'
        }
    },


답변

행위

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가 있습니다. 당신의 행동에서 약속을 돌려주는 것이 “필요한” 가 있습니다.

두 가지 다른 구성 요소에서 작업이 트리거 될 수 있고 각각 실패 사례를 다르게 처리하는 상황을 상상해보십시오. 이 경우 호출자 구성 요소를 매개 변수로 전달하여 상점에서 다른 플래그를 설정해야합니다.

멍청한 예

사용자가 navbar 및 / profile 페이지 (navbar 포함)에서 사용자 이름을 편집 할 수있는 페이지입니다. 둘 다 비동기식 인 “사용자 이름 변경”작업을 트리거합니다. 약속이 실패하면 페이지는 사용자가 사용자 이름을 변경하려는 구성 요소에만 오류를 표시해야합니다.

물론 멍청한 예이지만 코드를 복제하고 두 가지 다른 작업에서 동일한 호출을하지 않고는이 문제를 해결할 수있는 방법이 없습니다.


답변

actions.js

const axios = require('axios');
const types = require('./types');

export const actions = {
  GET_CONTENT({commit}){
    axios.get(`${URL}`)
      .then(doc =>{
        const content = doc.data;
        commit(types.SET_CONTENT , content);
        setTimeout(() =>{
          commit(types.IS_LOADING , false);
        } , 1000);
      }).catch(err =>{
        console.log(err);
    });
  },
}

home.vue

<script>
  import {value , onCreated} from "vue-function-api";
  import {useState, useStore} from "@u3u/vue-hooks";

  export default {
    name: 'home',

    setup(){
      const store = useStore();
      const state = {
        ...useState(["content" , "isLoading"])
      };
      onCreated(() =>{
        store.value.dispatch("GET_CONTENT" );
      });

      return{
        ...state,
      }
    }
  };
</script>


답변