ChatGPT解决这个技术问题 Extra ChatGPT

如何查看来自 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


t
tony19

例如,假设您有一篮水果,每次从篮子中添加或移除水果时,您希望 (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

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

计算属性和观察者

API 文档:计算

API 文档:观看


我只是想知道当 watch 操作应该分为两个步骤时我应该做什么:1)首先,检查所需数据是否被缓存以及它是否只是返回缓存的数据; 2) 如果缓存失败,我需要一个异步 ajax 操作来获取数据,但这似乎是 action 的工作。希望我的问题有意义,谢谢!
与 micah5 的答案相比,这有什么好处,它只是在组件中设置了一个观察者,关于存储值?它需要维护的代码更少。
@Exocentric当我写下答案时,我的问题并不清楚。没有上下文为什么需要监视属性。可以这样想:“我想观察变量 X,所以我可以做 Y。”可能这就是为什么大多数答案提出如此截然不同的方法的原因。没有人知道意图是什么。这就是我在回答中包含“目标”的原因。如果你有不同的目标,不同的答案可能适合他们。我的示例只是实验的起点。它并不是一个即插即用的解决方案。没有“好处”,因为好处取决于您的情况。
@1Cr18Ni9 我认为缓存不属于组件代码。您最终会过度设计一些应该非常简单的东西(获取数据并将其绑定到视图)。缓存已经在浏览器中实现。您可以通过从服务器发送正确的标头来利用它。这里的简单解释:csswizardry.com/2019/03/cache-control-for-civilians。您还可以查看 ServiceWorkers,它允许网站在没有互联网连接的情况下运行。
为什么要查看计算值?为什么计算的值不能为这个值创建一个工作表?这毕竟是计算值的重点。
S
Stephen Ostermiller

它很简单:

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

如果商店在一个模块中,请使用:

'$store.state.myModule.drawer'

对于嵌套文件,请使用:

'$store.state.fileOne.fileTwo.myModule.drawer'

这比这里的任何答案都更直截了当……有没有反对这样做的论据……?
太简单了,不像js,js一定更复杂。
如果是 function(n) { console.log(n); } 会更简单
超酷。也对这种方法的任何缺点感兴趣。到目前为止,它似乎运作良好。
顺便说一句,如果商店是用模块命名的,只需写 '$store.state.module.something'
s
smunk

你不应该使用组件的观察者来监听状态变化。我建议您使用 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


我不知道如何实现 mapGetters。你能给我举个例子吗。这将是一个很大的帮助。我现在只是执行 GONG 回答。泰
@Rbex“mapGetters”是“vuex”库的一部分。你不需要实现它。
这个答案是错误的。他实际上需要观察计算的属性。
一次调用的 getter 只会检索当时的状态。如果您希望该属性反映来自另一个组件的状态更改,您必须观察它。
为什么“你不应该使用组件的观察者来监听状态变化”?这是您可能没有想到的示例,如果我想从状态中查看令牌,以及何时更改为重定向到另一个页面。所以,在某些情况下你需要这样做。也许你需要更多的经验才能知道。
N
Nic Scozzaro

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

但在一些非常罕见的情况下,它可能对某人有用,所以我会留下这个答案。对于其他情况,请参阅@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.vuejs.org/en/getters.html#the-mapgetters-helper
@GabrielRobert 我认为两者都有一席之地。如果您需要基于响应式更改模板条件,则使用带有 mapState 的计算值等是有意义的。但除此之外,就像组件中的流量控制一样,您需要一个完整的监视。你是对的,你不应该使用普通的组件观察者,但是 state.$watch 是为这些用例设计的
每个人都提到它,但没有人说为什么!我正在尝试构建一个在更改时与数据库自动同步的 vuex 存储。我觉得看店是最无摩擦的方式!你怎么看?还是不是个好主意?
y
yeahdixon

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

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

      },
      {
        deep:true
      }
      );

这个应该叫哪里?
通过 this 访问 Vue 实例的地方。比如,一个 created 钩子。基本上,您需要的任何组件
t
tony19

这适用于所有无法使用 getter 解决问题并且实际上确实需要观察者的人,例如与非 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's doc 还提供了一个示例:

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

不错的 hack,但是太乏味了,你不觉得吗?
如果它在文档中,这不是黑客,是吗?但是,这也不是支持 vue/vuex 的理由
A
Adonis Gaitatzis

我确实尝试了一切以使其正常工作。

理论

我发现由于某种原因,从 $store 对对象的更改不一定会触发 .watch 方法。我的解决方法是

Store 创建一个复杂的数据集,它应该但不将更改传播到组件 在状态中创建一个递增计数器以充当标志,在监视时将更改传播到组件 在 $store.mutators 中创建一个方法以更改复杂数据集并增加计数器标志

创建一个复杂的数据集,该数据集应该但不会将更改传播到组件

在状态中创建一个递增计数器以充当标志,它会在监视时将更改传播到组件

在 $store.mutators 中创建一个方法来更改复杂数据集并增加计数器标志

组件监视 $store.state 标志的变化。当检测到更改时,从 $store.state 复杂数据集中更新本地相关的响应式更改 使用我们的 $store.mutators 方法对 $store.state 的数据集进行更改

注意 $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, // 对 objectData 的更改会在添加键时触发监视, // 但不会在修改值时触发? votes: { 'people ': 0, 'companies': 0, 'total': 0, }, }, 突变:{ 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() { // 在本地克隆相关数据 this.votesForPeople = this.$store .state.votes.people this.votesForCompanies = this.$store.state.votes.companies } } },方法:{ vote(event) { if (this.pendingVote) { this.$store.commit('vote', this.pendingVote) } } } })

People
公司


您遇到了 Vue 的反应性警告,这是有据可查的:一旦观察到,您就不能再将反应性属性添加到根数据对象。因此,建议在创建实例之前预先声明所有根级反应属性。
意思是,更改未预先定义 xxx 的 votes[xxx] 不会让您对这些值更改做出反应
有关此问题以及如何解决此问题的详细信息:vuejs.org/v2/guide/reactivity.html#For-Objects
@DerekPollard 当我尝试通过创建响应式组件来管理您引用的文档中建议的数据来解决此问题时,我的项目因超出递归循环计数器而崩溃,这对我来说意味着$store.state 的对象已经是反应式的。此外,当我手动验证 $store.state 数据已更改例如通过按钮单击 时,更改会反映在组件中,但此更改不会自动发生。上面的解决方案对我有用。我会喜欢更优雅的东西。
这里的答案是在你的突变中使用 Vue.set(state.votes, newVotesObject)
J
Jakub A Suplicki

如果您只是想观察一个状态属性,然后在组件内根据该属性的变化采取行动,请参见下面的示例。

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

我希望它有帮助!


Z
Zhang Sol

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

从“vue-property-decorator”导入{ Watch }; .. @Watch("$store.state.something") private watchSomething() { // 使用 this.$store.state.something 进行访问 ... }


为什么这被否决了?仅仅因为解决方案是针对 vue-class-component 并且 TO 要求使用旧的 vue-class 样式?我觉得前者更可取。也许@Zhang Sol 可以在介绍中提到,这是明确针对 vue-class-component 的?
请注意为什么打字稿装饰器比像这样简单的 vue 原生解决方案更可取:stackoverflow.com/a/56461539/3652783
@yann_yinn 很好,因为您的示例不适用于打字稿组件
@Desprit 是的,但问题既没有使用也没有提到 TypeScript。但是对于 Typscript 用户来说仍然是一个有用的提示。
M
Mukundhan

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

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

A
Amir

在计算中使用你的getter然后观察它并做你需要的

    computed:{
    ...mapGetters(["yourGetterName"])
 },
 watch: {
    yourGetterName(value) {
       // Do something you need
    },

  }

R
Rijosh

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

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 中的所有嵌套值。


t
tony19

观察商店变化的最佳方式是使用 Gabriel 所说的 mapGetters。但在某些情况下,您无法通过 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 will be updated only if this.id is changed

如果您希望在这种情况下更新组件,请使用 this.$store.watch solution provided by Gong。或者有意识地处理您的组件并在需要更新 todoById 时更新 this.id


谢谢你。这正是我的用例,确实无法观察到吸气剂......
至少在我的情况下,这有点不同 return this.$store.getters.getTodoById({id: this.id}) 不确定是否是导致 this 不响应的对象......但它不是响应的。
a
alloyking

您还可以订阅存储突变:

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

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


您可以在组件的 beforeMount() 挂钩中触发它,然后使用 if 语句过滤传入的突变。例如 if(mutation.type == "names/SET_NAMES") {... do something }
在我看来,这应该是公认的答案,因为它是基于 vuex 的,您可以选择状态变化的特定部分(mutation.type)
A
Andy

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

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

处理来自组件的 dispatch 状态操作的 store.state 更改不是一个好主意,因为此行为仅在您使用该组件时才有效。你也可能以无限循环结束。观察到 store.state 更改很少使用,例如,如果您有一个组件或页面应该根据 store.state 执行某些操作更改,而仅在您无法比较 newValueoldValue 的情况下使用计算的 mapState 无法处理
@Januartha 那么你对这个问题有什么建议呢?
@Andy 是的,当然是它的工作。我只想说明你为什么打电话给 store.dispatch?如果您想处理 store' why not handle it inside store.mutations` 的 store.state 更改?
@BillalBEGUERADJ 我更喜欢 dube 解决方案更清洁
@Januartha,因为在进行突变之前可能会发生 ajax 调用,这就是我首先使用 store.dispatch 的原因。例如,我想在 $store.state.country 更改时从一个国家/地区获取所有城市,因此我将其添加到观察者。然后我会写一个 ajax 调用:在 store.dispatch('fetchCities') 我写:axios.get('cities',{params:{country: state.country }}).then(response => store.commit('receiveCities',response) )
t
tony19

您可以使用 Vuex actionsgetterscomputed propertieswatchers 的组合来监听 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()}`)
    }
  }
})

See JSFiddle demo


ß
ßãlãjî

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
       }

    },

E
Eugene Kulakov

你也可以在你的 vue 组件中使用 mapState 来直接从 store 中获取状态。

在您的组件中:

computed: mapState([
  'my_state'
])

其中 my_state 是来自商店的变量。


s
semua bisa

====== store ===== import Vue from 'vue' import Vuex from 'vuex' import axios from 'axios' Vue.use(Vuex) export default new Vuex.Store({ state: { showRegisterLoginPage: true , 用户: null, allitem: null, productShow: null, userCart: null }, 突变: { 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 } },操作:{ 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.fi le) 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 has been 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 has已添加 ', 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}`,标题:{ token: localStorage.getItem('token') },数据:{ sesuatu: 'sesuatu' } }) .then(({ data }) => { count = data.count console.log(count, data) dispatch('getUserCart') }) .catch(err => { console.log(err) }) }, deleteTransactions({ dispatch }, transactionId) { axios( { 方法:'delete',url:`http://localhost:3000/transactions/${transactionId}`,标题:{ token: localStorage.getItem('token') } }) .then(({ data }) => { console.log('成功删除') dispatch('getUserCart') }) .catch(err => { console.log(e rr) }) } },模块:{} })


欢迎来到本站。只放一个代码片段是不够的。请提供有关您的代码的一些解释。
V
Vuong Tran

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

商店.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 中声明的名称匹配


O
Orhan Bayram

也可以用 debouncedWatch 安全观看(vue使用功能)

  debouncedWatch(
    lines,
    () => {
      console.log('changed');
    },
    500,
  );

k
kshitij

我使用计算的一个非常简单的方法是这样的。可能对你有任何帮助。

  const variable_name = computed(
        () => store.state.[name_of_state].property_name
      );

您可以执行此操作的另一个版本是

computed: {
  name () {
    return this.$store.state.[name_of_state].property
  }
}

这是一种从商店访问 getter 的格式。希望你有一个美好的一天。