166

我最近开始将东西从 jQ 迁移到更结构化的框架 VueJS,我喜欢它!

从概念上讲,Vuex 对我来说是一种范式转变,但我相信我现在知道它的全部内容,并且完全理解它!但是存在一些小的灰色区域,主要是从实施的角度来看。

这个我觉得设计的不错,但是不知道是不是和Vuex单向数据流的循环相矛盾。

基本上,从一个动作中返回一个 promise(-like) 对象被认为是一种好的做法吗?我将它们视为异步包装器,具有失败状态等,因此似乎很适合返回承诺。相反,mutators 只是改变事物,并且是存储/模块中的纯结构。

4

5 回答 5

309

actions在 Vuex 中是异步的。让调用函数(动作的发起者)知道动作已完成的唯一方法是返回一个 Promise 并稍后解决它。

这是一个示例:myAction返回 a 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返回 a是非常有益的Promise。否则,动作发起者无法知道正在发生的事情以及事情何时足够稳定以在用户界面上显示某些内容。

最后一点关于mutators- 正如你正确指出的那样,它们是同步的。它们在 中更改内容state,并且通常从 中调用actions。没有必要Promisesmutators, 作为actions手柄那部分混合。

编辑:我对单向数据流的 Vuex 循环的看法:

如果您访问this.$store.state["your data key"]组件中的数据,那么数据流是单向的。

行动的承诺只是让组件知道行动已经完成。

组件可以从上面示例中的 promise resolve 函数中获取数据(不是单向的,因此不推荐),或者直接从$store.state["your data key"]它是单向的并且遵循 vuex 数据生命周期。

上述段落假设您的 mutator 使用Vue.set(state, "your data key", http_data),一旦在您的操作中完成了 http 调用。

于 2016-10-21T02:38:19.490 回答
53

只是关于一个封闭主题的信息: 你不必创建一个承诺,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 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'
        }
    },
于 2018-10-03T08:38:32.070 回答
9

行动

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...
  }
})
于 2018-12-04T06:40:24.943 回答
1

TL:博士;仅在必要时从您的操作中返回承诺,但 DRY 链接相同的操作。

很长一段时间以来,我也认为返回动作与单向数据流的 Vuex 循环相矛盾。

但是,在某些极端情况下,从您的行为中返回承诺可能是“必要的”。

想象一下这样一种情况,可以从 2 个不同的组件触发一个操作,并且每个组件都以不同的方式处理故障情况。在这种情况下,需要将调用者组件作为参数传递以在商店中设置不同的标志。

愚蠢的例子

用户可以在导航栏和 /profile 页面(包含导航栏)中编辑用户名的页面。两者都会触发一个异步操作“更改用户名”。如果承诺失败,页面应该只在用户尝试更改用户名的组件中显示错误。

当然这是一个愚蠢的例子,但我没有看到解决这个问题的方法,而无需复制代码并在 2 个不同的操作中进行相同的调用。

于 2019-05-16T11:32:42.383 回答
-1

动作.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);
    });
  },
}

家.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>
于 2019-09-28T20:59:03.720 回答