vue.js 2 cara menonton nilai toko dari vuex


168

Saya menggunakan vuexdan vuejs 2bersama - sama.

Saya baru vuex, saya ingin menonton storeperubahan variabel.

Saya ingin menambahkan watchfungsi divue component

Inilah yang saya miliki sejauh ini:

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

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

Saya ingin tahu apakah ada perubahan dalam my_state

Bagaimana saya menonton store.my_statedi komponen vuejs saya?


gunakan plugin Vuejs yang datang dengan chrome itu akan berguna
AKASH PANDEY

Jawaban:


206

Katakanlah, misalnya, bahwa Anda memiliki sekeranjang buah-buahan, dan setiap kali Anda menambah atau menghapus buah dari keranjang, Anda ingin (1) menampilkan info tentang jumlah buah, tetapi Anda juga (2) ingin diberi tahu hitungan buah dalam beberapa mode mewah ...

buah-count-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>

Harap dicatat, bahwa nama fungsi di watchobjek, harus cocok dengan nama fungsi di computedobjek. Dalam contoh di atas namanya count.

Nilai baru dan lama dari properti yang ditonton akan diteruskan ke panggilan balik panggilan (fungsi hitungan) sebagai parameter.

Toko keranjang bisa terlihat seperti ini:

fruit-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

Anda dapat membaca lebih lanjut di sumber-sumber berikut:


Saya hanya ingin tahu apa yang harus saya lakukan ketika watchtindakan harus dibagi menjadi dua langkah: 1) Pertama, memeriksa apakah data keinginan di-cache dan apakah itu hanya mengembalikan data yang di-cache; 2) Jika cache gagal saya perlu tindakan aynx async untuk mengambil data, tetapi ini tampaknya menjadi actionpekerjaan. Semoga pertanyaan saya masuk akal, terima kasih!
1Cr18Ni9

Apa manfaatnya dari jawaban micah5 ini, yang hanya menentukan pengamat dalam komponen, pada nilai toko? Memiliki lebih sedikit kode untuk dipelihara.
Exocentric

@Eksentris Ketika saya menulis jawabannya, pertanyaan tidak jelas bagi saya. Tidak ada konteks mengapa diperlukan untuk menonton properti. Anggap saja seperti: "Saya ingin menonton variabel X, jadi saya bisa melakukan Y." Mungkin itu sebabnya sebagian besar jawaban mengusulkan pendekatan yang sangat berbeda. Tidak ada yang tahu apa tujuannya. Itu sebabnya saya memasukkan "tujuan" dalam jawaban saya. Jika Anda memiliki tujuan yang berbeda, jawaban yang berbeda mungkin cocok untuk mereka. Contoh saya hanyalah titik awal untuk eksperimen. Ini tidak dimaksudkan sebagai solusi plug & play. Tidak ada "manfaat", karena manfaat tergantung pada situasi Anda.
Anastazy

@ 1Cr18Ni9 Saya pikir caching tidak termasuk dalam kode komponen. Anda akan melakukan rekayasa berlebihan pada sesuatu yang seharusnya sangat sederhana (mengambil data dan mengikatnya ke tampilan). Caching sudah diterapkan di browser. Anda dapat memanfaatkannya dengan mengirim tajuk yang benar dari server. Penjelasan sederhana di sini: csswizardry.com/2019/03/cache-control-for-civilians . Anda juga dapat melihat di ServiceWorkers yang memungkinkan situs web untuk bekerja bahkan tanpa koneksi internet.
Anastazy

61

Anda tidak harus menggunakan pengamat komponen untuk mendengarkan perubahan status. Saya sarankan Anda untuk menggunakan fungsi getter dan memetakannya di dalam komponen Anda.

import { mapGetters } from 'vuex'

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

Di toko Anda:

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

Anda harus dapat mendengarkan perubahan apa pun yang dilakukan di toko Anda dengan menggunakan this.myState komponen Anda.

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


1
Saya tidak tahu bagaimana menerapkan mapGetters. Bisakah Anda menunjukkan saya sebuah contoh. Itu akan sangat membantu. Saya hanya menerapkan jawaban GONG saat ini. TY
Rbex

1
@Rbex "mapGetters" adalah bagian dari perpustakaan 'vuex'. Anda tidak perlu mengimplementasikannya.
Gabriel Robert

69
Jawaban ini salah. Dia benar-benar perlu menonton properti yang dihitung.
Juan

15
Sang pengambil yang dipanggil hanya akan mengambil status pada saat itu. Jika Anda ingin properti itu mencerminkan perubahan status dari komponen lain, Anda harus melihatnya.
C Tierney

3
Mengapa "Anda tidak boleh menggunakan pengamat komponen untuk mendengarkan perubahan status"? Berikut ini adalah contoh yang mungkin tidak Anda pikirkan, jika saya ingin menonton token dari negara, dan ketika itu berubah untuk mengarahkan ulang ke halaman lain. jadi, ada beberapa kasus yang perlu Anda lakukan. mungkin Anda perlu lebih banyak pengalaman untuk mengetahuinya.
Shlomi Levi

46

Sesederhana:

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

6
Ini adalah pandangan yang lebih langsung daripada jawaban di sini ... apakah ada argumen yang menentang melakukan hal ini ..?
Inigo

19
Ini terlalu sederhana sehingga tidak terlihat seperti js, js pasti lebih rumit.
gali

1
Akan lebih simpel jika itufunction(n) { console.log(n); }
WofWca

2
Sangat keren. Tertarik juga pada kelemahan dari pendekatan ini. Sejauh ini tampaknya berfungsi dengan baik.
namero999

1
Serius. Tampaknya ini jauh lebih baik daripada jawaban yang diterima, yang membutuhkan nama fungsi yang digandakan dalam pengawasan dan dikomputasi. Bisakah seorang pakar mengomentari mengapa atau mengapa tidak melakukannya dengan cara ini?
Exocentric

42

Seperti disebutkan di atas, bukan ide yang baik untuk menonton perubahan secara langsung di toko

Tetapi dalam beberapa kasus yang sangat jarang mungkin bermanfaat bagi seseorang, jadi saya akan meninggalkan jawaban ini. Untuk kasus lain, silakan lihat jawaban @ gabriel-robert

Anda dapat melakukan ini state.$watch. Tambahkan ini dalam createdmetode Anda (atau di mana Anda perlu ini dieksekusi) dalam komponen

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

Lebih detail: https://vuex.vuejs.org/api/#watch


3
Saya tidak berpikir itu ide yang baik untuk menonton negara secara langsung. Kita harus menggunakan getter. vuex.vuejs.org/en/getters.html#the-mapgetters-helper
Gabriel Robert

14
@GabrielRobert Saya pikir ada tempat untuk keduanya. Jika Anda perlu secara reaktif mengubah kondisi templat berdasarkan, menggunakan nilai yang dihitung dengan mapState, dll masuk akal. Tetapi jika tidak, seperti untuk kontrol aliran yang rata pada suatu komponen, Anda memerlukan arloji penuh. Anda benar, Anda tidak boleh menggunakan pengamat komponen biasa, tetapi negara. $ Jam dirancang untuk kasus penggunaan ini
roberto tomás

14
Semua orang menyebutkannya, tetapi tidak ada yang mengatakan mengapa! Saya mencoba membangun toko vuex yang disinkronkan secara otomatis dengan DB saat perubahan. Saya merasa pengamat di toko adalah cara paling tanpa gesekan! Bagaimana menurut anda? Masih bukan ide yang bagus?
mesqueeb

16

Saya pikir si penanya ingin menggunakan arloji dengan Vuex.

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

      },
      {
        deep:true
      }
      );

13

Ini untuk semua orang yang tidak dapat menyelesaikan masalah mereka dengan getter dan sebenarnya sangat membutuhkan pengamat, misalnya untuk berbicara dengan hal-hal pihak ketiga yang tidak terkait (lihat Vue Watchers tentang kapan harus menggunakan pengamat).

Pengamat komponen Vue dan nilai yang dihitung keduanya juga bekerja pada nilai yang dihitung. Jadi tidak berbeda dengan vuex:

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

jika hanya tentang menggabungkan keadaan lokal dan global, dokumen mapState juga memberikan contoh:

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

hack yang bagus, tapi terlalu membosankan, bukan begitu?
Martian2049

2
Bukan hack jika ada di dokumen, bukan? Tapi kemudian, itu juga bukan argumen untuk vue / vuex
dube

8

jika Anda menggunakan naskah maka Anda dapat:

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

..

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


Mengapa ini benar-benar diturunkan? Hanya karena solusinya adalah untuk komponen vue-class dan TO sedang meminta gaya vue-class lama? Saya menemukan yang pertama lebih disukai. Mungkin @Zhang Sol dapat menyebutkan dalam pendahuluan, bahwa ini secara eksplisit untuk komponen-vue-class?
JackLeEmmerdeur

Catat yakin mengapa dekorator naskah lebih disukai daripada solusi asli vue sesederhana yang ini: stackoverflow.com/a/56461539/3652783
yann_yinn

6

Buat status lokal variabel toko Anda dengan menonton dan mengatur perubahan nilai. Sedemikian rupa sehingga perubahan variabel lokal untuk input-bentuk v-model tidak secara langsung bermutasi variabel toko .

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

5

Cara terbaik untuk menonton perubahan toko adalah menggunakan mapGettersseperti yang dikatakan Gabriel. Tetapi ada kasus ketika Anda tidak bisa melakukannya mapGettersmisalnya Anda ingin mendapatkan sesuatu dari toko menggunakan parameter:

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

dalam hal ini Anda tidak dapat menggunakan mapGetters. Anda dapat mencoba melakukan sesuatu seperti ini sebagai gantinya:

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

Namun sayangnya todoById akan diperbarui hanya jika this.iddiubah

Jika Anda ingin Anda memperbarui komponen dalam this.$store.watch solusi kasus penggunaan seperti yang disediakan oleh Gong . Atau tangani komponen Anda secara sadar dan perbarui this.idsaat Anda perlu memperbarui todoById.


Terima kasih. Itulah tepatnya kasus penggunaan saya, dan memang rajin rajin menontonnya ...
pscheit

5

Jika Anda hanya ingin menonton sebuah milik negara dan kemudian bertindak dalam komponen sesuai dengan perubahan properti yang kemudian melihat contoh di bawah ini.

Di store.js:

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

Dalam skenario ini, saya membuat booleanproperti negara yang akan saya ubah di berbagai tempat dalam aplikasi seperti:

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

Sekarang, jika saya perlu menonton properti negara bagian itu di beberapa komponen lain dan kemudian mengubah properti lokal saya akan menulis yang berikut di mountedhook:

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

Pertama, saya mengatur pengamat pada properti negara dan kemudian dalam fungsi panggilan balik saya menggunakan valueproperti itu untuk mengubah localProperty.

Saya harap ini membantu!


3

Ketika Anda ingin menonton di tingkat negara bagian, itu bisa dilakukan dengan cara ini:

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

Itu bukan ide yang baik untuk menangani store.stateperubahan dengan dispatchtindakan negara dari komponen karena perilaku ini hanya berfungsi jika Anda menggunakan komponen itu. Anda juga mungkin berakhir dengan loop tak terbatas. Tonton untuk store.stateperubahan jarang digunakan, misalnya jika Anda memiliki komponen atau halaman yang harus melakukan beberapa tindakan berdasarkan store.stateperubahan yang tidak dapat ditangani dengan menggunakan mapState yang dikomputasi hanya di mana Anda tidak dapat membandingkan newValuevsoldValue
Januartha

@ Januartha apa saran Anda untuk masalah ini?
Billal Begueradj

@Andy ya tentu saja ini berfungsi. Saya hanya ingin mencatat mengapa Anda menelepon store.dispatch? jika Anda ingin menangani store.stateperubahan untuk store' why not handle it inside store.mutations`?
Januartha

@BillalBEGUERADJ saya prever dube solusi yang lebih bersih
Januartha

@ Januartha, karena mungkin ada panggilan ajax terjadi sebelum melakukan mutasi, itu sebabnya saya gunakan store.dispatchdulu. Misalnya, saya ingin mendapatkan semua kota dari suatu negara setiap kali ada $store.state.countryperubahan, jadi saya menambahkan ini ke pengamat. Maka saya akan menulis panggilan ajax: di store.dispatch('fetchCities')saya menulis:axios.get('cities',{params:{country: state.country }}).then(response => store.commit('receiveCities',response) )
Andy

2

Anda dapat menggunakan kombinasi tindakan Vuex , getter , properti yang dihitung , dan pengamat untuk mendengarkan perubahan pada nilai status Vuex.

Kode HTML:

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

Kode JavaScript:

'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()}`)
    }
  }
})

Lihat demo JSFiddle .


1

Anda juga dapat berlangganan mutasi toko:

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

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


Anda dapat menjalankan ini di kait beforeMount () pada komponen Anda kemudian memfilter mutasi yang masuk dengan Pernyataan if. misal if (mutation.type == "names / SET_NAMES") {... do something}
Alejandro

1

Di dalam komponen, buat fungsi yang dikomputasi

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

Sekarang nama fungsi yang dihitung dapat ditonton, seperti

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

Perubahan yang dibuat di vuexnegara bagian my_stateakan mencerminkan fungsi yang dihitungmyState dan memicu fungsi arloji.

Jika negara my_statememiliki data bersarang, maka handleropsi akan membantu lebih banyak

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

Ini akan menonton semua nilai bersarang di toko my_state.


0

Anda juga dapat menggunakan mapState di komponen vue Anda untuk mengarahkan status dari store.

Di komponen Anda:

computed: mapState([
  'my_state'
])

Di mana my_statevariabel dari toko.


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
Selamat datang di situs ini. Menempatkan potongan kode saja tidak cukup. Harap berikan beberapa penjelasan tentang kode Anda.
pgk

0

Saya menggunakan cara ini dan berhasil:

store.js:

const state = {
  createSuccess: false
};

mutations.js

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

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

Dan di komponen Anda di mana Anda menggunakan status dari toko:

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

Saat pengguna mengirimkan formulir, tindakan STORE akan dipanggil, setelah berhasil dibuat, mutasi CREATE_SUCCESS dilakukan setelah itu. Hidupkan createSuccess benar, dan dalam komponen, pengamat akan melihat nilai telah berubah dan memicu pemberitahuan.

isSuccess harus sesuai dengan nama yang Anda nyatakan di getters.js

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.