vue.js 2 vuex'ten mağaza değerlerini izleme


169

Birlikte vuexve vuejs 2birlikte kullanıyorum .

Ben yeniyim vuex, storedeğişken bir değişiklik izlemek istiyorum .

Bu watchişlevivue component

Şimdiye kadar sahip olduğum şey bu:

import Vue from 'vue';
import {
  MY_STATE,
} from './../../mutation-types';

export default {
  [MY_STATE](state, token) {
    state.my_state = token;
  },
};

Ben herhangi bir değişiklik olup olmadığını bilmek istiyorum my_state

store.my_stateVuejs bileşenimde nasıl izlerim ?


krom ile birlikte gelen bir Vuejs eklentisi kullanın
AKASH PANDEY

Yanıtlar:


206

Örneğin, bir meyve sepetiniz olduğunu ve sepete her meyve eklediğinizde veya sepetten her meyve çıkardığınızda (1) meyve sayısı hakkında bilgi görüntülemek istediğinizi, ancak (2) bazı süslü bir şekilde meyve sayısı ...

Meyve-sayımı-component.vue

<template>
  <!-- We meet our first objective (1) by simply -->
  <!-- binding to the count property. -->
  <p>Fruits: {{ count }}</p>
</template>

<script>
import basket from '../resources/fruit-basket'

export default () {
  computed: {
    count () {
      return basket.state.fruits.length
      // Or return basket.getters.fruitsCount
      // (depends on your design decisions).
    }
  },
  watch: {
    count (newCount, oldCount) {
      // Our fancy notification (2).
      console.log(`We have ${newCount} fruits now, yay!`)
    }
  }
}
</script>

watchNesnedeki işlevin adının, computednesnedeki işlevin adıyla eşleşmesi gerektiğini lütfen unutmayın . Yukarıdaki örnekte adı count.

İzlenen bir özelliğin yeni ve eski değerleri, parametre olarak geri izleme (sayım işlevi) öğesine aktarılır.

Sepet dükkanı şöyle görünebilir:

Meyve-basket.js

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const basket = new Vuex.Store({
  state: {
    fruits: []
  },
  getters: {
    fruitsCount (state) {
      return state.fruits.length
    }
  }
  // Obviously you would need some mutations and actions,
  // but to make example cleaner I'll skip this part.
})

export default basket

Aşağıdaki kaynaklardan daha fazla bilgi edinebilirsiniz:


Sadece watcheylemin iki adıma bölünmesi gerektiğinde ne yapacağımı merak ediyorum : 1) İlk olarak, arzu verilerinin önbelleğe alınmış olup olmadığını ve sadece önbelleğe alınmış verileri döndürüp döndürmediğini kontrol edin; 2) Önbellek başarısız olursa, verileri almak için bir zaman uyumsuz ajax eylemine ihtiyacım var, ama bu action'iş gibi görünüyor . Sorumun umuduyla, teşekkür ederim!
1Cr18Ni9

Bunun, bileşende bir izleyiciyi mağaza değerine ayarlayan micah5'in cevabına göre avantajı nedir? Korunması daha az kod içerir.
Exosentric

@Exocentric Cevabı yazdığımda soru benim için net değildi. Mülkleri izlemek için neden gerekli olduğu bağlamı yoktur. Bunu şöyle düşünün: "Değişken X'i izlemek istiyorum, böylece Y yapabilirim." Muhtemelen bu yüzden cevapların çoğu çok farklı yaklaşımlar önermektedir. Kimse niyetin ne olduğunu bilmiyor. Bu yüzden cevabıma "hedefler" ekledim. Farklı hedefleriniz varsa, farklı cevaplar bunlara uygun olabilir. Örneğim sadece deneme için bir başlangıç ​​noktası. Bir tak ve çalıştır çözümü olması amaçlanmamıştır. "Fayda" yoktur, çünkü faydalar durumunuza bağlıdır.
Anastazy

@ 1Cr18Ni9 Önbelleğe almanın bileşen koduna ait olmadığını düşünüyorum. Son derece basit bir şeye aşırı mühendislik uygulayacaksınız (veri getirme ve görünüme bağlama). Önbellekleme tarayıcıda zaten uygulanmış. Sunucudan doğru başlıklar göndererek bundan faydalanabilirsiniz. Burada basit açıklama: csswizardry.com/2019/03/cache-control-for-civilians . Web sitesinin internet bağlantısı olmadan bile çalışmasına izin veren ServiceWorkers'a da göz atabilirsiniz.
Anastazy

61

Durum değişikliğini dinlemek için bileşenin izleyicilerini kullanmamalısınız. Alıcı işlevlerini kullanmanızı ve bunları bileşeninizin içinde eşlemenizi öneririm.

import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters({
      myState: 'getMyState'
    })
  }
}

Mağazanızda:

const getters = {
  getMyState: state => state.my_state
}

this.myStateBileşeninizi kullanarak mağazanızda yaptığınız değişiklikleri dinleyebilmeniz gerekir .

https://vuex.vuejs.org/en/getters.html#the-mapgetters-helper


1
MapGetters uygulamasını nasıl yapacağımı bilmiyorum. Beni bir örneğe yönlendirebilir misin? Çok yardımcı olur. Şu anda sadece GONG cevabını uyguluyorum. TY
Rbex

1
@Rbex "mapGetters", "vuex" kütüphanesinin bir parçasıdır. Uygulamanıza gerek yok.
Gabriel Robert

69
Bu cevap yanlış. Aslında hesaplanmış özellikleri izlemesi gerekiyor.
Juan

15
Alıcı bir kez çağrıldığında yalnızca o sırada durumu alır. Bu özelliğin durum değişikliğini başka bir bileşenden yansıtmasını istiyorsanız onu izlemeniz gerekir.
C Tierney

3
Neden "Durum değişikliğini dinlemek için bileşen izleyicilerini kullanmamalısınız"? Aşağıda, belirteci eyaletten izlemek istersem ve başka bir sayfaya yönlendirme olarak değiştirdiğimde düşünemeyebileceğiniz bir örnek. yani, bunu yapmanız gereken bazı durumlar var. belki bunu bilmek için daha fazla deneyime ihtiyacınız vardır.
Shlomi Levi

48

Bu kadar basit:

watch: {
  '$store.state.drawer': function() {
    console.log(this.$store.state.drawer)
  }
}

6
Bu, buradaki cevapların herhangi birinden daha basit bir manzara ... Bunu yapmaya karşı herhangi bir tartışma var mı?
Inigo

19
Çok basit yani js gibi görünmüyor, js daha karmaşık olmalı.
digout

1
Eğer olsaydı daha da kolay olurdufunction(n) { console.log(n); }
WofWca

2
Süper havalı. Bu yaklaşımın herhangi bir dezavantajı ile de ilgileniyorum. Şimdiye kadar iyi çalışıyor gibi görünüyor.
namero999

1
Ciddi anlamda. Bu, saatte ve hesaplanmış yinelenen işlev adları gerektiren kabul edilen yanıttan çok daha iyi görünüyor. Bir uzman bunu neden yapmalı veya yapmamalı hakkında yorum yapabilir mi?
Exosentric

43

Yukarıda belirtildiği gibi, değişiklikleri doğrudan mağazada izlemek iyi bir fikir değildir

Ama bazı çok nadir durumlarda birisi için yararlı olabilir, bu yüzden bu cevabı bırakacağım. Diğer durumlar için lütfen @ gabriel-robert cevabına bakınız.

Bunu yapabilirsiniz state.$watch. Bunu created, bileşeninizde (veya bunun yürütülmesi gereken yere) yönteminize ekleyin

this.$store.watch(
    function (state) {
        return state.my_state;
    },
    function () {
        //do something on data change
    },
    {
        deep: true //add this if u need to watch object properties change etc.
    }
);

Daha fazla detay: https://vuex.vuejs.org/api/#watch


3
Durumu doğrudan izlemenin iyi bir fikir olduğunu sanmıyorum. Alıcıları kullanmalıyız. vuex.vuejs.org/en/getters.html#the-mapgetters-helper
Gabriel Robert

14
@GabrielRobert Bence her ikisi için de bir yer var. Şablon koşullarını reaktif olarak değiştirmeniz gerekiyorsa, mapState vb. İle hesaplanan bir değer kullanmak mantıklıdır. Ancak aksi halde, bir bileşendeki eşit akış kontrolü gibi, tam bir saate ihtiyacınız vardır. Haklısınız, düz bileşenli izleyiciler kullanmamalısınız, ancak devlet. $ Watch bu kullanım durumları için tasarlanmıştır
roberto tomás

14
Herkes bundan bahsediyor, ama kimse nedenini söylemiyor! Değişiklikler üzerine bir DB ile otomatik olarak senkronize edilmiş bir vuex mağaza oluşturmaya çalışıyorum. Mağazadaki gözlemcilerin en sürtünmesiz yol olduğunu hissediyorum! Ne düşünüyorsun? Hala iyi bir fikir değil mi?
mesqueeb

16

Bence asker Vuex ile saat kullanmak istiyor.

this.$store.watch(
      (state)=>{
        return this.$store.getters.your_getter
      },
      (val)=>{
       //something changed do something

      },
      {
        deep:true
      }
      );

13

Bu, sorunlarını alıcılarla çözemeyen ve aslında gerçekten bir izleyiciye ihtiyaç duyan tüm insanlar içindir, örneğin vue olmayan üçüncü taraflarla konuşmak için (bkz. Vue Watchers gözlemcileri ne zaman kullanılacağı hakkında).

Vue bileşeninin izleyicileri ve hesaplanan değerlerin her ikisi de hesaplanan değerler üzerinde çalışır. Bu yüzden vuex ile farklı değil:

import { mapState } from 'vuex';

export default {
    computed: {
        ...mapState(['somestate']),
        someComputedLocalState() {
            // is triggered whenever the store state changes
            return this.somestate + ' works too';
        }
    },
    watch: {
        somestate(val, oldVal) {
            // is triggered whenever the store state changes
            console.log('do stuff', val, oldVal);
        }
    }
}

yalnızca yerel ve küresel durumu birleştirmekle ilgiliyse , mapState'in dokümanı da bir örnek sunar:

computed: {
    ...mapState({
        // to access local state with `this`, a normal function must be used
        countPlusLocalState (state) {
          return state.count + this.localCount
        }
    }
})

güzel bir hack, ama çok sıkıcı, değil mi?
Martian2049

2
Dokümanlardaysa bir hack değil, değil mi? Ama sonra, o da vue / vuex için yanlısı bir argüman değil
dube

8

typescript kullanıyorsanız şunları yapabilirsiniz:

import { Watch } from "vue-property-decorator";

..

@Watch("$store.state.something")
private watchSomething() {
   // use this.$store.state.something for access
   ...
}


Bu neden tam olarak reddedildi? Çözüm vue sınıfı bileşen için olduğu ve TO'nun eski vue sınıfı stiller istediği için mi? Birincisini tercih edilebilir buluyorum. Belki de @Zhang Sol girişte, bunun açıkça vue-class-bileşeni için olduğunu söyleyebilir mi?
JackLeEmmerdeur

Bir daktilo dekoratörünün neden bu kadar basit bir vue yerel çözümüne tercih edileceğine dikkat edin: stackoverflow.com/a/56461539/3652783
yann_yinn

6

Değer değişikliklerini izleyip ayarlayarak mağaza değişkeninizin Yerel durumunu oluşturun . Form-giriş v-modeli için yerel değişken değişiklikleri , depo değişkenini doğrudan değiştirmez .

data() {
  return {
    localState: null
  };
 },
 computed: {
  ...mapGetters({
    computedGlobalStateVariable: 'state/globalStateVariable'
  })
 },
 watch: {
  computedGlobalStateVariable: 'setLocalState'
 },
 methods: {
  setLocalState(value) {
   this.localState = Object.assign({}, value);
  }
 }

5

Mağaza değişikliklerini izlemenin en iyi yolu mapGettersGabriel'in dediği gibi kullanmaktır . Ancak bunu yapamadığınız bir durum var, mapGettersörneğin parametre kullanarak mağazadan bir şey almak istiyorsunuz:

getters: {
  getTodoById: (state, getters) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

bu durumda kullanamazsınız mapGetters. Bunun yerine böyle bir şey yapmaya çalışabilirsiniz:

computed: {
    todoById() {
        return this.$store.getters.getTodoById(this.id)
    }
}

Ancak maalesef todoById yalnızca this.iddeğiştirilirse güncellenecek

Böyle bir durumda bileşen güncellemesini istiyorsanız this.$store.watch , Gong tarafından sağlanan çözümü kullanın . Veya bileşeninizi bilinçli bir şekilde kullanın ve güncellemeniz this.idgerektiğinde güncelleyin todoById.


teşekkür ederim. Bu tam olarak benim kullanım durumum ve gerçekten alıcı o zaman
izlenemez

5

Sadece bir devlet mülkünü izlemek istiyorsanız ve ardından bu özelliğin değişikliklerine göre bileşen içinde hareket aşağıdaki örneğe bakın.

İçinde store.js:

export const state = () => ({
 isClosed: false
})
export const mutations = {
 closeWindow(state, payload) {
  state.isClosed = payload
 }
}

Bu senaryoda, ben booleanböyle uygulamada farklı yerlerde değişecek bir devlet özelliği oluşturuyorum :

this.$store.commit('closeWindow', true)

Şimdi, ben bu özelliği başka bir bileşen izlemek ve sonra yerel özelliği değiştirmek gerekiyorsa ben mountedkanca aşağıdaki yazmak istiyorum :

mounted() {
 this.$store.watch(
  state => state.isClosed,
  (value) => {
   if (value) { this.localProperty = 'edit' }
  }
 )
}

İlk olarak, state özelliği üzerinde bir izleyici ayarlıyorum ve sonra geri arama işlevinde ben valuedeğiştirmek için bu özelliği kullanın localProperty.

Umut ediyorum bu yardım eder!


3

Eyalet düzeyinde izlemek istediğinizde, bu şekilde yapılabilir:

let App = new Vue({
    //...
    store,
    watch: {
        '$store.state.myState': function (newVal) {
            console.log(newVal);
            store.dispatch('handleMyStateChange');
        }
    },
    //...
});

Bu davranış yalnızca bu bileşeni kullandığınızda çalıştığından, bileşenden durum eylemine store.stategöre değişikliği işlemek iyi bir fikir değildir dispatch. Ayrıca sonsuz döngü ile sona erebilir. store.stateNadiren değiştirmek için izleyin , örneğin, store.statehesaplanmış mapState'i kullanarak yalnızca karşılaştıramayacağınız yerde değiştirilemeyen bir eylem veya işlem yapmanız gereken bir bileşen veya sayfanız varsanewValueoldValue
Januartha

@Januartha o zaman bu soruna önerileriniz neler?
Billal Begueradj

@ Ve evet elbette onun işi. Sadece neden aradığını not etmek istiyorum store.dispatch? Eğer işlemek istiyorsanız store.statebozabilir store' why not handle it inside store.mutations`?
Januartha

@BillalBEGUERADJ ben prever dube çözümü daha temizleyici
Januartha

@Januartha, bir mutasyon yapmadan önce gerçekleşecek bir ajax çağrısı olabilir, bu yüzden store.dispatchönce kullanıyorum. Örneğin, bir ülkedeki tüm şehirleri her $store.state.countrydeğiştiğinde almak istiyorum , bu yüzden bunu gözlemciye ekliyorum. Sonra ben bir ajax çağrı yazmak istiyorsunuz: içinde store.dispatch('fetchCities')ben yazmak:axios.get('cities',{params:{country: state.country }}).then(response => store.commit('receiveCities',response) )
Andy

2

Vuex durum değerindeki değişiklikleri dinlemek için Vuex eylemlerini , alıcıları , hesaplanan özellikleri ve izleyicileri bir arada kullanabilirsiniz .

HTML Kodu:

<div id="app" :style='style'>
  <input v-model='computedColor' type="text" placeholder='Background Color'>
</div>

JavaScript Kodu:

'use strict'

Vue.use(Vuex)

const { mapGetters, mapActions, Store } = Vuex

new Vue({
    el: '#app',
  store: new Store({
    state: {
      color: 'red'
    },
    getters: {
      color({color}) {
        return color
      }
    },
    mutations: {
      setColor(state, payload) {
        state.color = payload
      }
    },
    actions: {
      setColor({commit}, payload) {
        commit('setColor', payload)
      }
    }
  }),
  methods: {
    ...mapGetters([
        'color'
    ]),
    ...mapActions([
        'setColor'
    ])
  },
  computed: {
    computedColor: {
        set(value) {
        this.setColor(value)
      },
      get() {
        return this.color()
      }
    },
    style() {
        return `background-color: ${this.computedColor};`
    }
  },
  watch: {
    computedColor() {
        console.log(`Watcher in use @${new Date().getTime()}`)
    }
  }
})

JSFiddle demosuna bakın .


1

Mağaza mutasyonlarına da abone olabilirsiniz:

store.subscribe((mutation, state) => {
  console.log(mutation.type)
  console.log(mutation.payload)
})

https://vuex.vuejs.org/api/#subscribe


Bunu, bileşeninizin beforeMount () kancasında çalıştırabilir ve sonra gelen mutasyonları bir if Deyimi ile filtreleyebilirsiniz. örneğin, eğer (mutation.type == "names / SET_NAMES") {... bir şeyler yapın}
Alejandro

1

Bileşenin içinde, hesaplanmış bir işlev oluşturun

computed:{
  myState:function(){
    return this.$store.state.my_state; // return the state value in `my_state`
  }
}

Şimdi hesaplanan işlev adı,

watch:{
  myState:function(newVal,oldVal){
    // this function will trigger when ever the value of `my_state` changes
  }
}

Yapılan değişiklikler vuexdevlet my_statebilgisayarlı işlevinde yansıtacaktır myStateve saat fonksiyonu tetikler.

Devlet ise my_stateiç içe verilere sahip, o handlerseçenek daha yardımcı olacaktır

watch:{
  myState:{
    handler:function(newVal,oldVal){
      // this function will trigger when ever the value of `my_state` changes
    },
    deep:true
  }
}

Bu, mağazadaki tüm iç içe değerleri izleyecektir my_state.


0

Mağazadan alma durumunu yönlendirmek için vue bileşeninizde mapState'i de kullanabilirsiniz.

Bileşeninizde:

computed: mapState([
  'my_state'
])

my_stateMağazadan bir değişken nerede .


0

====== store =====
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    showRegisterLoginPage: true,
    user: null,
    allitem: null,
    productShow: null,
    userCart: null
  },
  mutations: {
    SET_USERS(state, payload) {
      state.user = payload
    },
    HIDE_LOGIN(state) {
      state.showRegisterLoginPage = false
    },
    SHOW_LOGIN(state) {
      state.showRegisterLoginPage = true
    },
    SET_ALLITEM(state, payload) {
      state.allitem = payload
    },
    SET_PRODUCTSHOW(state, payload) {
      state.productShow = payload
    },
    SET_USERCART(state, payload) {
      state.userCart = payload
    }
  },
  actions: {
    getUserLogin({ commit }) {
      axios({
        method: 'get',
        url: 'http://localhost:3000/users',
        headers: {
          token: localStorage.getItem('token')
        }
      })
        .then(({ data }) => {
          // console.log(data)
          commit('SET_USERS', data)
        })
        .catch(err => {
          console.log(err)
        })
    },
    addItem({ dispatch }, payload) {
      let formData = new FormData()
      formData.append('name', payload.name)
      formData.append('file', payload.file)
      formData.append('category', payload.category)
      formData.append('price', payload.price)
      formData.append('stock', payload.stock)
      formData.append('description', payload.description)
      axios({
        method: 'post',
        url: 'http://localhost:3000/products',
        data: formData,
        headers: {
          token: localStorage.getItem('token')
        }
      })
        .then(({ data }) => {
          // console.log('data hasbeen created ', data)
          dispatch('getAllItem')
        })
        .catch(err => {
          console.log(err)
        })
    },
    getAllItem({ commit }) {
      axios({
        method: 'get',
        url: 'http://localhost:3000/products'
      })
        .then(({ data }) => {
          // console.log(data)
          commit('SET_ALLITEM', data)
        })
        .catch(err => {
          console.log(err)
        })
    },
    addUserCart({ dispatch }, { payload, productId }) {
      let newCart = {
        count: payload
      }
      // console.log('ini dari store nya', productId)

      axios({
        method: 'post',
        url: `http://localhost:3000/transactions/${productId}`,
        data: newCart,
        headers: {
          token: localStorage.getItem('token')
        }
      })
        .then(({ data }) => {
          dispatch('getUserCart')
          // console.log('cart hasbeen added ', data)
        })
        .catch(err => {
          console.log(err)
        })
    },
    getUserCart({ commit }) {
      axios({
        method: 'get',
        url: 'http://localhost:3000/transactions/user',
        headers: {
          token: localStorage.getItem('token')
        }
      })
        .then(({ data }) => {
          // console.log(data)
          commit('SET_USERCART', data)
        })
        .catch(err => {
          console.log(err)
        })
    },
    cartCheckout({ commit, dispatch }, transactionId) {
      let count = null
      axios({
        method: 'post',
        url: `http://localhost:3000/transactions/checkout/${transactionId}`,
        headers: {
          token: localStorage.getItem('token')
        },
        data: {
          sesuatu: 'sesuatu'
        }
      })
        .then(({ data }) => {
          count = data.count
          console.log(count, data)

          dispatch('getUserCart')
        })
        .catch(err => {
          console.log(err)
        })
    },
    deleteTransactions({ dispatch }, transactionId) {
      axios({
        method: 'delete',
        url: `http://localhost:3000/transactions/${transactionId}`,
        headers: {
          token: localStorage.getItem('token')
        }
      })
        .then(({ data }) => {
          console.log('success delete')

          dispatch('getUserCart')
        })
        .catch(err => {
          console.log(err)
        })
    }
  },
  modules: {}
})


1
Siteye hoş geldiniz. Yalnızca bir kod pasajı koymak yeterli değildir. Lütfen kodunuzla ilgili bazı açıklamalar sağlayın.
pgk

0

Bu şekilde kullandım ve işe yarıyor:

store.js:

const state = {
  createSuccess: false
};

mutations.js

[mutations.CREATE_SUCCESS](state, payload) {
    state.createSuccess = payload;
}

actions.js

async [mutations.STORE]({ commit }, payload) {
  try {
    let result = await axios.post('/api/admin/users', payload);
    commit(mutations.CREATE_SUCCESS, user);
  } catch (err) {
    console.log(err);
  }
}

getters.js

isSuccess: state => {
    return state.createSuccess
}

Ve mağazadan durumu kullandığınız bileşeninizde:

watch: {
    isSuccess(value) {
      if (value) {
        this.$notify({
          title: "Success",
          message: "Create user success",
          type: "success"
        });
      }
    }
  }

Kullanıcı form gönderdiğinde, oluşturulan MAĞAZA eylemi çağrılır , bundan sonra CREATE_SUCCESS mutasyonu işlenir . Çevirin createSuccess doğrudur ve bileşende, izleyici değer değişti ve tetik bildirim gelmiştir göreceksiniz.

isSuccess , getters.js'de bildirdiğiniz adla eşleşmelidir

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.