vue.js 2如何从vuex看存储值


168

我使用vuexvuejs 2在一起。

我是的新手vuex,我想观看store变量更改。

我想watch在我的功能添加vue component

这是我到目前为止的内容:

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

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

我想知道是否有任何变化 my_state

如何观看store.my_state我的vuejs组件?


使用带有chrome的Vuejs插件会很方便
AKASH PANDEY

Answers:


205

举例来说,假设您有一个水果篮,并且每次在水果篮中添加或删除水果时,您都想要(1)显示有关水果计数的信息,但是您也希望(2)收到有关以某种幻想的方式计算水果的数量...

水果计数组件

<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

watched属性的新旧值将作为参数传递到watch回调(count函数)中。

篮子商店可能看起来像这样:

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

您可以在以下资源中阅读更多内容:


我只是想知道watch应该将操作分为两个步骤时该怎么做:1)首先,检查所需数据是否已缓存,并且是否确实返回了缓存的数据;2)如果缓存失败,我需要一个异步ajax操作来获取数据,但这似乎是action工作。希望我的问题有意义,谢谢!
1Cr18Ni9

与micah5的答案相比,这样做有什么好处,而micah5的答案只是将组件中的观察者设置为商店价值?它需要维护的代码更少。
凌晨

@Exocentric当我写下答案时,问题对我来说还不清楚。没有上下文为什么需要监视属性。可以这样想:“我想观看变量X,所以我可以做Y。” 也许这就是为什么大多数答案都提出了截然不同的方法的原因。没有人知道它的意图。这就是为什么我在回答中包含“目标”的原因。如果您有不同的目标,则可能会采用不同的答案。我的示例只是实验的起点。它并不意味着是即插即用的解决方案。没有“收益”,因为收益取决于您的情况。
Anastazy

@ 1Cr18Ni9我认为缓存不属于组件代码。您最终将过度设计应该非常简单的东西(获取数据并将其绑定到视图)。缓存已在浏览器中实现。您可以通过从服务器发送正确的标头来利用它。这里的简单说明:csswizardry.com/2019/03/cache-control-for-civilians。您也可以看一下ServiceWorkers,即使没有互联网连接,也可以让网站正常工作。
Anastazy

61

您不应使用组件的观察程序来监听状态变化。我建议您使用getters函数,然后将其映射到组件中。

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


1
我不知道如何实现mapGetters。你能指出一个例子吗?这将是一个很大的帮助。我现在只执行GONG答案。TY
Rbex

1
@Rbex“ mapGetters”是'vuex'库的一部分。您不需要实现它。
加百利·罗伯

69
这个答案是错误的。他实际上需要监视计算的属性。
胡安

15
曾经调用过的getter只会在那个时候检索状态。如果您希望该属性反映其他组件的状态更改,则必须对其进行监视。
C Tierney

3
为什么“您不应该使用组件的观察程序来监听状态变化”?这是您可能没有想到的示例,如果我想从状态监视令牌,以及当令牌更改为重定向到另一个页面时。因此,在某些情况下您需要这样做。也许您需要更多的经验才能知道这一点。
Shlomi Levi

45

就像这样简单:

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

6
这真是该死的景象,比这​​里的任何答案都更直接……是否有反对这样做的论点..?
Inigo

19
它太简单了,所以看起来不像js,js必须更复杂。
挖出

1
如果是的话,甚至会更简单function(n) { console.log(n); }
WofWca

2
超酷。也对这种方法的任何缺点感兴趣。到目前为止,它似乎运行良好。
namero999

1
说真的 这似乎比接受的答案要好得多,后者需要在watch中进行重复的函数名并进行计算。专家可以评论为什么或为什么不这样做吗?
凌晨

42

如上所述,直接在商店中查看更改不是一个好主意

但在某些非常罕见的情况下,它可能对某人有用,所以我将保留此答案。对于其他情况,请参阅@ 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


3
我认为直接观察状态不是一个好主意。我们应该使用吸气剂。vuex.vuejs.org/en/getters.html#the-mapgetters-helper
Gabriel Robert

14
@GabrielRobert我认为两者都有一个地方。如果您需要基于反应性更改模板条件,则将计算值与mapState等配合使用是有意义的。但是否则,就像在组件中进行流量控制一样,您也需要全面监视。没错,您不应该使用简单的组件观察程序,而是使用state。$ watch专为这些用例而设计
robertotomás'17

14
每个人都提到它,但是没有人说为什么!我正在尝试构建一个vuex存储,该存储在更改后会与数据库自动同步。我觉得商店里的观察员是最轻松的方式!你怎么看?还是个好主意?
mesqueeb

16

我认为提问者想与Vuex一起使用手表。

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

      },
      {
        deep:true
      }
      );

13

这适用于所有无法使用吸气剂解决问题并且实际上确实需要观察员的人,例如与非Vue第三方交流(请参阅Vue Watchers,了解何时使用观察器)。

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

不错,但是太乏味了,您不觉得吗?
Martian2049

2
如果在文档中,这不是hack,不是吗?但是,这也不是vue / vuex的有利论据
dube

8

如果您使用打字稿,则可以:

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

..

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


为什么要对此一票否定?仅仅是因为解决方案是针对vue-class-component的,而TO却要求使用旧的vue-class样式?我发现前者更好。也许@Zhang Sol在引言中可能提到,这明确地是针对vue-class-component的?
JackLeEmmerdeur

请注意,为什么打字稿装饰器会比像这样的简单vue本机解决方案更可取:stackoverflow.com/a/56461539/3652783
yann_yinn

6

通过观察和设置值更改来创建商店变量的本地状态。这样,表单输入v模型的局部变量更改不会直接更改存储变量

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

5

mapGetters正如Gabriel所说,观察商店变化的最好方法是使用。但是在mapGetters某些情况下,您可能无法通过例如通过参数从商店中获取一些东西来完成它:

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更改后才会更新

如果您希望在这种情况下更新组件,请使用this.$store.watch Gong提供的解决方案。或自觉处理组件并this.id在需要更新时进行更新todoById


谢谢。那恰好是我的用例,然后确实看不到吸气剂了……
pscheit

5

如果您只想观察一个state属性,然后根据该属性的更改在组件内进行操作,请参见以下示例。

store.js

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

在这种情况下,我将创建一个boolean状态属性,该属性将在应用程序的不同位置进行更改,如下所示:

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

现在,如果我需要在其他组件中观察该state属性,然后更改local属性,则可以在mounted钩子中编写以下内容:

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

首先,我在state属性上设置了一个观察者,然后在回调函数中使用该value属性的来更改localProperty

希望对您有所帮助!


3

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

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

处理组件的store.statedispatch状态操作变化不是一个好主意,因为只有在使用该组件时,此行为才起作用。另外,您可能会以无限循环结束。观看store.state更改很少使用,例如,如果您有一个组件或页面应根据store.state更改执行某些操作,而这些更改或更改只能在无法比较newValuevs的情况下进行,而使用mapState则无法处理oldValue
Januartha,

@Januartha那么您对这个问题有何建议?
Billal Begueradj

@Andy当然是工作。我只想指出您为什么打电话store.dispatch?如果您想处理store.mutations`的store.state更改store' why not handle it inside
Januartha '18

@BillalBEGUERADJ我以前的杜比解决方案更干净
Januartha

@Januartha,因为在进行突变之前可能会有一个ajax调用发生,所以这就是我store.dispatch首先使用的原因。例如,无论何时$store.state.country发生变化,我都希望从一个国家/地区获取所有城市,因此我将其添加到观察程序中。然后我会写一个ajax调用:在store.dispatch('fetchCities')我写:axios.get('cities',{params:{country: state.country }}).then(response => store.commit('receiveCities',response) )
Andy

2

您可以结合使用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演示


1

您还可以订阅商店突变:

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

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


您可以在组件的beforeMount()挂钩中触发此操作,然后使用if语句过滤传入的突变。例如,如果(mutation.type ==“ names / SET_NAMES”){...做某事}
Alejandro,

1

在组件内部,创建一个计算函数

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,并触发监控功能。

如果状态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



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
欢迎来到该网站。仅放置代码段是不够的。请提供有关您的代码的一些说明。
pgk

0

我用这种方式,它的工作原理:

store.js:

const state = {
  createSuccess: false
};

突变.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
}

在您使用商店状态的组件中:

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

用户提交表单时,将调用操作STORE,创建成功后,将提交CREATE_SUCCESS突变。将createSuccess设置为true,然后在组件中,观察者将看到值已更改并触发通知。

isSuccess应该与您在getters.js中声明的名称匹配

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.