Подтвердить что ты не робот

Возврат Promises из действий Vuex

Недавно я начал переносить вещи из jQ в более структурированную структуру, являющуюся VueJS, и мне это нравится!

Концептуально, Vuex был для меня немного изменением парадигмы, но я уверен, что знаю, что все это сейчас, и полностью получить его! Но есть несколько небольших серых областей, в основном с точки зрения реализации.

Этот, который я чувствую, хорош по дизайну, но не знаю, противоречит ли он Vuex для потока однонаправленного потока.

В принципе, считается хорошей практикой возвращать объект обещания (как) из действия? Я рассматриваю их как асинхронные обертки, состояния отказов и т.д., Поэтому кажется, что это хорошо подходит для возврата обещания. Напротив, мутаторы просто меняют вещи и являются чистыми структурами внутри хранилища/модуля.

4b9b3361

Ответ 1

actions в Vuex являются асинхронными. Единственный способ позволить вызывающей функции (инициатору действия) знать, что действие завершено, - это вернуть обещание и разрешить его позже.

Вот пример: 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 очень полезно вернуть a Promise. В противном случае инициатор действия не сможет узнать, что происходит, и когда все достаточно стабильно, чтобы показать что-то в пользовательском интерфейсе.

И последнее примечание к mutators - как вы правильно указали, они синхронны. Они меняют материал в state и обычно вызываются из actions. Нет необходимости смешивать Promises с mutators, так как дескриптор actions обрабатывает эту часть.

Изменить: Мои взгляды на цикл Vuex однонаправленного потока данных:

Если вы получаете доступ к данным типа this.$store.state["your data key"] в своих компонентах, то поток данных является однонаправленным.

Обещание от действия заключается только в том, чтобы компонент знал, что действие завершено.

Компонент может либо взять данные из функции разрешения обещаний в приведенном выше примере (не однонаправленный, поэтому не рекомендуется), либо непосредственно из $store.state["your data key"], который является однонаправленным и следует за жизненным циклом данных vuex.

В приведенном выше абзаце предполагается, что ваш мутатор использует Vue.set(state, "your data key", http_data), как только HTTP-вызов будет завершен в вашем действии.

Ответ 2

Просто для информации по закрытой теме: вам не нужно создавать обещание, 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) => {
            console.log(response);
            commit('logUserIn',response.data.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
        });
    },

Ответ 3

действия

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

Ответ 4

TL: DR; возвращайте обещания от ваших действий только тогда, когда это необходимо, но СУХОЙ цепочке одни и те же действия

В течение долгого времени я также думал, что возвратные действия противоречат циклу однонаправленного потока данных Vuex.

Но есть крайние случаи, когда возвращение обещания от ваших действий может быть "необходимым".

Представьте себе ситуацию, когда действие может быть запущено из 2 разных компонентов, и каждый обрабатывает случай сбоя по-своему. В этом случае необходимо передать компонент вызывающей стороны в качестве параметра для установки различных флагов в хранилище.

Тупой пример

Страница, на которой пользователь может редактировать имя пользователя в панели навигации и на странице/профиля (которая содержит панель навигации). Оба запускают действие "изменить имя пользователя", которое является асинхронным. Если обещание не выполняется, на странице должна отображаться только ошибка в компоненте, с которого пользователь пытался изменить имя пользователя.

Конечно, это глупый пример, но я не вижу способа решить эту проблему без дублирования кода и выполнения одного и того же вызова в двух разных действиях.

Ответ 5

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>