繁体   English   中英

如何查看来自 vuex 的存储值?

[英]How to watch store values from vuex?

我正在一起使用vuexvuejs 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)
})

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

您可以使用 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()}`)
    }
  }
})

请参阅 JSFiddle 演示

当您想在状态级别观看时,可以通过以下方式完成:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM