[英]How to watch store values from vuex?
我正在一起使用vuex
和vuejs 2
。
我是vuex
的新手,我想觀察store
變量的變化。
我想在我的vue component
中添加watch
功能
這是我到目前為止所擁有的:
import Vue from 'vue';
import {
MY_STATE,
} from './../../mutation-types';
export default {
[MY_STATE](state, token) {
state.my_state = token;
},
};
我想知道my_state
是否有任何變化
如何在我的 vuejs 組件中觀看store.my_state
?
例如,假設您有一籃水果,每次從籃子中添加或移除水果時,您希望 (1) 顯示有關水果數量的信息,但您還 (2) 希望收到通知以某種花哨的方式數水果……
水果計數組件.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>
請注意, watch
對象中的函數名稱必須與computed
對象中的函數名稱匹配。 在上面的示例中,名稱是count
。
監視屬性的新舊值將作為參數傳遞給監視回調(計數函數)。
籃子商店可能如下所示:
水果籃.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
您可以在以下資源中閱讀更多內容:
它很簡單:
watch: {
'$store.state.drawer': function() {
console.log(this.$store.state.drawer)
}
}
如果商店在一個模塊中,請使用:
'$store.state.myModule.drawer'
對於嵌套文件,請使用:
'$store.state.fileOne.fileTwo.myModule.drawer'
你不應該使用組件的觀察者來監聽狀態變化。 我建議您使用 getter 函數,然后將它們映射到您的組件中。
import { mapGetters } from 'vuex'
export default {
computed: {
...mapGetters({
myState: 'getMyState'
})
}
}
在您的商店中:
const getters = {
getMyState: state => state.my_state
}
您應該能夠通過在組件中使用this.myState
來收聽對商店所做的任何更改。
https://vuex.vuejs.org/en/getters.html#the-mapgetters-helper
如上所述,直接在商店中查看更改並不是一個好主意
但在一些非常罕見的情況下,它可能對某人有用,所以我會留下這個答案。 對於其他情況,請參閱@gabriel-robert 回答
你可以通過state.$watch
做到這一點。 將此添加到組件中您created
的(或您需要執行的)方法中
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.
}
);
更多細節: https ://vuex.vuejs.org/api/#watch
我認為提問者想將手表與 Vuex 一起使用。
this.$store.watch(
(state)=>{
return this.$store.getters.your_getter
},
(val)=>{
//something changed do something
},
{
deep:true
}
);
這適用於所有無法使用 getter 解決問題並且實際上確實需要觀察者的人,例如與非 vue 第三方的東西交談(有關何時使用觀察者的信息,請參閱Vue觀察者)。
Vue 組件的觀察者和計算值都適用於計算值。 所以與 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);
}
}
}
如果只是結合本地和全局狀態, mapState 的文檔還提供了一個示例:
computed: {
...mapState({
// to access local state with `this`, a normal function must be used
countPlusLocalState (state) {
return state.count + this.localCount
}
}
})
我確實嘗試了一切以使其正常工作。
我發現出於某種原因,從$store
對對象的更改不一定會觸發.watch
方法。 我的解決方法是
state
中創建一個遞增計數器以充當標志,它會在監視時將更改傳播到組件$store.mutators
中創建一個方法來更改復雜數據集並增加計數器標志$store.state
標志的變化。 當檢測到更改時,從$store.state
復雜數據集中更新本地相關的響應式更改$store.mutators
方法更改$store.state
的數據集這是這樣實現的:
店鋪
let store = Vuex.Store({
state: {
counter: 0,
data: { someKey: 0 }
},
mutations: {
updateSomeKey(state, value) {
update the state.data.someKey = value;
state.counter++;
}
}
});
零件
data: {
dataFromStoreDataSomeKey: null,
someLocalValue: 1
},
watch: {
'$store.state.counter': {
immediate: true,
handler() {
// update locally relevant data
this.someLocalValue = this.$store.state.data.someKey;
}
}
},
methods: {
updateSomeKeyInStore() {
this.$store.commit('updateSomeKey', someLocalValue);
}
這很復雜,但基本上在這里我們正在觀察一個標志的變化,然后更新本地數據以反映存儲在$state
中的對象的重要變化
Vue.config.devtools = false const store = new Vuex.Store({ state: { voteCounter: 0, // changes to objectData trigger a watch when keys are added, // but not when values are modified? votes: { 'people': 0, 'companies': 0, 'total': 0, }, }, mutations: { vote(state, position) { state.votes[position]++; state.voteCounter++; } }, }); app = new Vue({ el: '#app', store: store, data: { votesForPeople: null, votesForCompanies: null, pendingVote: null, }, computed: { totalVotes() { return this.votesForPeople + this.votesForCompanies }, peoplePercent() { if (this.totalVotes > 0) { return 100 * this.votesForPeople / this.totalVotes } else { return 0 } }, companiesPercent() { if (this.totalVotes > 0) { return 100 * this.votesForCompanies / this.totalVotes } else { return 0 } }, }, watch: { '$store.state.voteCounter': { immediate: true, handler() { // clone relevant data locally this.votesForPeople = this.$store.state.votes.people this.votesForCompanies = this.$store.state.votes.companies } } }, methods: { vote(event) { if (this.pendingVote) { this.$store.commit('vote', this.pendingVote) } } } })
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script> <script src="https://unpkg.com/vuex@3.5.1/dist/vuex.js"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css"> <div id="app"> <form @submit.prevent="vote($event)"> <div class="form-check"> <input class="form-check-input" type="radio" name="vote" id="voteCorps" value="companies" v-model="pendingVote" > <label class="form-check-label" for="voteCorps"> Equal rights for companies </label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="vote" id="votePeople" value="people" v-model="pendingVote" > <label class="form-check-label" for="votePeople"> Equal rights for people </label> </div> <button class="btn btn-primary" :disabled="pendingVote==null" >Vote</button> </form> <div class="progress mt-2" v-if="totalVotes > 0" > <div class="progress-bar" role="progressbar" aria-valuemin="0" :style="'width: ' + peoplePercent + '%'" :aria-aluenow="votesForPeople" :aria-valuemax="totalVotes" >People</div> <div class="progress-bar bg-success" role="progressbar" aria-valuemin="0" :style="'width: ' + companiesPercent + '%'" :aria-valuenow="votesForCompanies" :aria-valuemax="totalVotes" >Companies</div> </div> </div>
如果您只是想觀察一個狀態屬性,然后在組件內根據該屬性的變化采取行動,請參見下面的示例。
在store.js
:
export const state = () => ({
isClosed: false
})
export const mutations = {
closeWindow(state, payload) {
state.isClosed = payload
}
}
在這種情況下,我正在創建一個boolean
狀態屬性,我將在應用程序的不同位置進行更改,如下所示:
this.$store.commit('closeWindow', true)
現在,如果我需要在其他組件中查看該狀態屬性,然后更改本地屬性,我將在mounted
的鈎子中編寫以下內容:
mounted() {
this.$store.watch(
state => state.isClosed,
(value) => {
if (value) { this.localProperty = 'edit' }
}
)
}
首先,我在 state 屬性上設置了一個觀察者,然后在回調函數中我使用該屬性的value
來更改localProperty
。
我希望它有幫助!
如果您使用打字稿,那么您可以:
import { Watch } from "vue-property-decorator"; .. @Watch("$store.state.something") private watchSomething() { // use this.$store.state.something for access ... }
通過觀察和設置值變化來創建存儲變量的本地狀態。 這樣表單輸入 v-model的局部變量更改不會直接改變存儲變量。
data() {
return {
localState: null
};
},
computed: {
...mapGetters({
computedGlobalStateVariable: 'state/globalStateVariable'
})
},
watch: {
computedGlobalStateVariable: 'setLocalState'
},
methods: {
setLocalState(value) {
this.localState = Object.assign({}, value);
}
}
在計算中使用你的getter然后觀察它並做你需要的
computed:{
...mapGetters(["yourGetterName"])
},
watch: {
yourGetterName(value) {
// Do something you need
},
}
觀察商店變化的最佳方式是使用 Gabriel 所說的mapGetters
。 但是有一種情況是你不能通過mapGetters
,例如你想使用參數從 store 中獲取一些東西:
getters: {
getTodoById: (state, getters) => (id) => {
return state.todos.find(todo => todo.id === id)
}
}
在這種情況下,您不能使用mapGetters
。 您可以嘗試執行以下操作:
computed: {
todoById() {
return this.$store.getters.getTodoById(this.id)
}
}
但不幸的是todoById
只有在this.id
改變時才會更新
如果您希望在這種情況下更新組件,請使用 Gong 提供的this.$store.watch
解決方案。 或者有意識地處理你的組件並在需要更新this.id
時更新todoById
。
在組件內部,創建一個計算函數
computed:{
myState:function(){
return this.$store.state.my_state; // return the state value in `my_state`
}
}
現在可以查看計算出的函數名稱,例如
watch:{
myState:function(newVal,oldVal){
// this function will trigger when ever the value of `my_state` changes
}
}
在vuex
狀態my_state
中所做的更改將反映在計算函數myState
並觸發 watch 函數。
如果狀態my_state
具有嵌套數據,則handler
選項將提供更多幫助
watch:{
myState:{
handler:function(newVal,oldVal){
// this function will trigger when ever the value of `my_state` changes
},
deep:true
}
}
這將監視存儲my_state
中的所有嵌套值。
您還可以訂閱存儲突變:
store.subscribe((mutation, state) => {
console.log(mutation.type)
console.log(mutation.payload)
})
您可以使用 Vuex動作、 getter 、計算屬性和觀察者的組合來監聽 Vuex 狀態值的變化。
HTML 代碼:
<div id="app" :style='style'>
<input v-model='computedColor' type="text" placeholder='Background Color'>
</div>
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()}`)
}
}
})
當您想在狀態級別觀看時,可以通過以下方式完成:
let App = new Vue({
//...
store,
watch: {
'$store.state.myState': function (newVal) {
console.log(newVal);
store.dispatch('handleMyStateChange');
}
},
//...
});
Vue 在字符串狀態下觀察
狀態:
$store.state.local_store.list_of_data
內部組件
watch: {
'$store.state.local_store.list_of_data':{//<----------your state call in string
handler(){
console.log("value changeing in party sales entry"); //<---do your stuff here
},
deep:true
}
},
你也可以在你的 vue 組件中使用 mapState 來直接從 store 中獲取狀態。
在您的組件中:
computed: mapState([
'my_state'
])
其中my_state
是來自商店的變量。
====== 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: {} })
我用這種方式,它的工作原理:
商店.js:
const state = {
createSuccess: false
};
突變.js
[mutations.CREATE_SUCCESS](state, payload) {
state.createSuccess = payload;
}
動作.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
}
在您使用商店狀態的組件中:
watch: {
isSuccess(value) {
if (value) {
this.$notify({
title: "Success",
message: "Create user success",
type: "success"
});
}
}
}
當用戶提交表單時,將調用操作STORE ,創建成功后,將提交CREATE_SUCCESS突變。 將createSuccess 設為true,並且在組件中,watcher 將看到 value 已更改並觸發通知。
isSuccess應該與您在getters.js中聲明的名稱匹配
也可以用 debouncedWatch 安全觀看(vue使用功能)
debouncedWatch(
lines,
() => {
console.log('changed');
},
500,
);
我使用計算的一個非常簡單的方法是這樣的。 可能對你有任何幫助。
const variable_name = computed(
() => store.state.[name_of_state].property_name
);
您可以執行此操作的另一個版本是
computed: {
name () {
return this.$store.state.[name_of_state].property
}
}
這是一種從商店訪問 getter 的格式。 希望你有一個美好的一天。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.