Vuex eylemlerinden Geri Dönen Vaatler


131

Son zamanlarda jQ'dan VueJS olan daha yapılandırılmış bir çerçeveye bir şeyler taşımaya başladım ve buna bayılıyorum!

Kavramsal olarak, Vuex benim için biraz paradigma değişikliği oldu, ancak şimdi ne olduğunu bildiğime ve tamamen anladığıma eminim! Ancak, çoğu uygulama açısından bakıldığında, birkaç küçük gri alan vardır.

Bunun tasarım gereği iyi olduğunu düşünüyorum, ancak tek yönlü veri akışının Vuex döngüsüyle çelişip çelişmediğini bilmiyorum .

Temel olarak, bir eylemden vaat edilen (benzeri) bir nesneyi iade etmek iyi bir uygulama olarak kabul edilir mi? Bunları başarısızlık durumları ve benzeri durumlarla eşzamansız sarmalayıcılar olarak ele alıyorum, bu yüzden bir söz vermek için iyi bir uygun gibi görünüyor. Aksine, mutatörler sadece bir şeyleri değiştirirler ve bir mağaza / modül içindeki saf yapılardır.

Yanıtlar:


256

actionsVuex'te eşzamansızdır. Çağıran işlevin (eylemin başlatıcısı) bir eylemin tamamlandığını bilmesine izin vermenin tek yolu, bir Söz vermek ve daha sonra çözümlemektir.

İşte bir örnek: a myActiondöndürür Promise, bir http çağrısı yapar ve Promisesonrasını çözer veya reddeder - tümü eşzamansız olarak

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

Şimdi, Vue bileşeniniz başladığında, myActionbu Promise nesnesini alacak ve başarılı olup olmadığını bilebilir. Vue bileşeni için bazı örnek kodlar:

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

Yukarıda görebileceğiniz gibi, actionsa döndürmek oldukça faydalıdır Promise. Aksi takdirde, eylem başlatıcının ne olduğunu ve işlerin kullanıcı arayüzünde bir şey gösterecek kadar kararlı olduğunu bilmesinin bir yolu yoktur.

Ve ile ilgili son bir not mutators- haklı olarak belirttiğiniz gibi, bunlar eşzamanlıdır. İçindeki şeyleri değiştirirler stateve genellikle den çağrılırlar actions. Karıştırmak için gerek yoktur Promisesile mutatorsolduğu gibi, actionsbu kısmı sapın.

Düzenleme: Tek yönlü veri akışının Vuex döngüsü hakkındaki görüşlerim:

Verilere this.$store.state["your data key"]bileşenlerinizdeki gibi erişirseniz , veri akışı tek yönlüdür.

Eylemden gelen vaat, yalnızca bileşenin eylemin tamamlandığını bilmesini sağlamaktır.

Bileşen, yukarıdaki örnekteki vaat çözümleme işlevinden veri alabilir (tek yönlü değildir, bu nedenle önerilmez) veya doğrudan $store.state["your data key"]tek yönlü olup vuex veri yaşam döngüsünü izler.

Yukarıdaki paragraf Vue.set(state, "your data key", http_data), eyleminizde http çağrısı tamamlandıktan sonra, mutatörünüzün kullandığını varsayar .


4
"Yukarıda görebileceğiniz gibi, eylemlerin bir Sözü geri vermesi son derece yararlıdır. Aksi takdirde, eylem başlatanın ne olduğunu ve işlerin kullanıcı arayüzünde bir şeyi gösterecek kadar kararlı olduğunu bilmesinin bir yolu yoktur." IMO, bu Vuex noktasını kaçırıyor. Eylem başlatanın ne olduğunu bilmesine gerek yoktur . İşlem, veriler eşzamansız olaydan geri geldiğinde durumu değiştirmeli ve bileşen bu aşama değişikliğine bir Promise değil, Vuex deposunun durumuna göre yanıt vermelidir.
ceejayoz

1
@ceejayoz Kabul edildi, devlet tüm veri nesneleri için tek doğruluk kaynağı olmalıdır. Ancak Söz, eylemi başlatan kişiyle iletişime geçmenin tek yoludur. Örneğin, http başarısızlığından sonra bir "Tekrar Dene" düğmesi göstermek isterseniz, bu bilgi duruma geçemez, ancak yalnızca bir Promise.reject().
Mani

1
Bu, Vuex mağazasında kolayca ele alınabilir. Eylemin kendisi , bileşenin üstesinden gelebileceği bir failedmutatörü ateşleyebilir state.foo.failed = true. Bunun için söz konusu bileşene geçilmesine gerek yoktur ve bonus olarak, aynı başarısızlığa tepki vermek isteyen başka herhangi bir şey mağazadan da bunu yapabilir.
ceejayoz

4
@ceejayoz Dokümanlardaki - vuex.vuejs.org/en/actions.html - Oluşturma Eylemlerine (son bölüm) bakın - eylemler eşzamansızdır ve bu nedenle, bu belgelerde belirtildiği gibi bir Söz vermek iyi bir fikirdir. Yukarıdaki $ http durumunda olmayabilir, ancak başka bir durumda bir işlemin ne zaman tamamlandığını bilmemiz gerekebilir.
Mani

6
@DanielPark Evet, senaryoya ve bireysel geliştirici tercihlerine "bağlıdır". Benim durumumda, benim durumumdaki gibi ara değerlerden kaçınmak istedim {isLoading:true}ve bu nedenle Promises'e başvurdum. Tercihleriniz değişebilir. Günün sonunda amacımız, dağınıklığı olmayan ve bakımı kolay kodlar yazmaktır. Sözün bu hedefe ulaşıp ulaşmayacağı veya belirsizlik durumu - karar verecek bireysel geliştiricilere ve ekiplere bırakılmıştır.
Mani

41

Sadece kapalı bir konu hakkında bilgi almak için: bir söz oluşturmanız gerekmez, axios bir söz verir:

Referans: https://forum.vuejs.org/t/how-to-resolve-a-promise-object-in-a-vuex-action-and-redirect-to-another-route/18254/4

Misal:

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

Başka bir örnek:

    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 ile başka bir örnek

    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'
        }
    },

Axios eylemleri varsayılan olarak zaten eşzamansız olduğu için son örnek gereksiz olmamalı mı?
nonNumericalFloat

9

Hareketler

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

Bileşen

this.$store.dispatch('ADD_PRODUCT',data).then((res) => {
  if (res.status === 'success') {
    // write your success actions here....
  } else {
     // write your error actions here...
  }
})

2
bu çalışmıyor yanıtı bileşende tanımlanmamış
Nand Lal

1
ADD_PRODUCT işlevine dönüş eklemeyi unuttuğunuzu düşünüyorum
Bhaskararao Gummidi

"Axios" ta "a" küçük harf olmalıdır.
bigp

Axois'i 'axios'tan ithal eden şirket olarak aldım
Bhaskararao Gummidi

0

TP: DR; sadece gerekli olduğunda sizden vaatleri iade edin, ancak aynı eylemleri KURU zincirleme.

Uzun zamandır, geri dönen eylemlerin tek yönlü veri akışının Vuex döngüsüyle çeliştiğini düşündüm.

Ancak, eylemlerinizden bir sözün geri verilmesinin "gerekli" olabileceği KENAR DURUMLAR vardır .

Bir eylemin 2 farklı bileşenden tetiklenebildiği ve her birinin arıza durumunu farklı şekilde ele aldığı bir durum hayal edin. Bu durumda, mağazada farklı bayraklar ayarlamak için arayan bileşeninin bir parametre olarak iletilmesi gerekecektir.

Aptal örnek

Kullanıcının kullanıcı adını navbar'da ve / profile sayfasında (navbar'ı içeren) düzenleyebileceği sayfa. Her ikisi de zaman uyumsuz olan bir "kullanıcı adını değiştir" eylemini tetikler. Söz başarısız olursa, sayfa yalnızca kullanıcının kullanıcı adını değiştirmeye çalıştığı bileşende bir hata görüntülemelidir.

Elbette aptalca bir örnek ama bu sorunu kodu kopyalamadan ve aynı çağrıyı 2 farklı eylemde yapmadan çözmenin bir yolunu göremiyorum.


-1

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>
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.