vuejs 2如何从vuex中观察商店价值

时间:2017-04-07 05:13:22

标签: javascript vue.js vuejs2 vuex

我一起使用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

是否有任何变化

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

19 个答案:

答案 0 :(得分:109)

比方说,你有一篮水果, 每次你从篮子里添加或删除水果,你 想要(1)显示有关水果数量的信息,您还希望(2)希望以某种奇特的方式获得水果数量的通知......

果计数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, yaay!`)
    }
  }
}
</script>

请注意,watch对象中函数的名称必须与computed对象中函数的名称匹配。在上面的示例中,名称为count

监视属性的新旧值将作为参数传递给监视回调(计数函数)。

篮子商店看起来像这样:

果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
    }
  }
  // Obvously you would need some mutations and actions,
  // but to make example cleaner I'll skip this part.
})

export default basket

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

答案 1 :(得分:62)

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

答案 2 :(得分:33)

如上所述,直接在商店中观看更改

并不是一个好主意

但在一些非常罕见的情况下,它可能对某人有用,所以我会留下这个答案。对于其他情况,请参阅@ 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/en/api.html#vuex-store-instance-methods

答案 3 :(得分:12)

我认为提问者想要使用Vuex手表。

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

      },
      {
        deep:true
      }
      );

答案 4 :(得分:7)

这适用于所有无法用吸气剂解决问题但真正需要观察者的人,例如:与非第三方的东西交谈(关于何时使用观察者,请参阅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
        }
    }
})

答案 5 :(得分:4)

通过观察和设置值更改,

为商店变量创建本地状态。 这样,对于 form-input v-model 的局部变量更改不会直接更改 store变量

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

答案 6 :(得分:4)

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

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

答案 7 :(得分:4)

观看商店变化的最佳方式是使用Error:(17, 0) Could not find method maven() for arguments [build_2rpdxydj6arlyq4m2v87kde3g$_run_closure1$_closure2$_closure3@70ca8e63] on object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler. ,正如加布里埃尔所说。 但有一种情况是,您无法通过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) } } will be updated only if this.id is changed

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

答案 8 :(得分:2)

这很简单:

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

答案 9 :(得分:1)

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

答案 10 :(得分:1)

当你想在州一级观看时,可以这样做:

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

答案 11 :(得分:1)

You could also subscribe to the store mutations:

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

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

答案 12 :(得分:1)

如果您只是想监视一个州财产,然后根据该财产的更改在主管内行事,则请参见以下示例。

@Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { baseViewFragmentImageView = inflater.inflate(R.layout.fragment_image_view, container, false); unbinder = ButterKnife.bind(this, baseViewFragmentImageView); getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); if (bundle != null) { iv.setPhotoUri(Uri.fromFile(new File(bundle.getString("ImageFilePath")))); iv.setTransitionName(bundle.getString("transition_name")); ViewCompat.setTransitionName(iv, bundle.getString("transition_name")); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { TransitionSet transitionSet = new TransitionSet(); transitionSet.addTransition(new ChangeBounds()); transitionSet.addTarget(iv); getDialog().getWindow().setSharedElementEnterTransition(transitionSet); this.setSharedElementReturnTransition(new ImageTransition()); } return baseViewFragmentImageView; } 中:

store.js

在这种情况下,我将创建一个export const state = () => ({ isClosed: false }) export const mutations = { closeWindow(state, payload) { state.isClosed = payload } } 状态属性,该属性将在应用程序的不同位置进行更改,如下所示:

boolean

现在,如果我需要在其他组件中观察该state属性,然后更改local属性,则可以在this.$store.commit('closeWindow', true) 钩子中编写以下内容:

mounted

首先,我要在state属性上设置观察者,然后在回调函数中使用该属性的mounted() { this.$store.watch( state => state.isClosed, (value) => { if (value) { this.localProperty = 'edit' } } ) } 来更改value

希望对您有帮助!

答案 13 :(得分: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: {}
})

答案 14 :(得分:0)

我使用了这种方式,并且有效:

store.js:

const state = {
  createSuccess: false
};

mutations.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

中声明的名称匹配

答案 15 :(得分:0)

您还可以在vue组件中使用mapState来指示从商店获取状态。

在您的组件中:

computed: mapState([
  'my_state'
])

其中my_state是商店的变量。

答案 16 :(得分:0)

我尽一切努力使它正常工作。

理论

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

  • 商店
    • 创建一个复杂的数据集,该集应该将更改传播到组件
    • state中创建一个递增计数器以用作标志,这样做在观看时会将更改传播到组件
    • $store.mutators中创建一个方法来更改复杂数据集并增加计数器标记
  • 组件
    • 注意$store.state标志中的更改。检测到更改后,请从$store.state复杂数据集中更新本地相关的反应性更改
    • 使用我们的$store.state方法对$store.mutators的数据集进行更改

实施

这是这样实现的:

商店

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>

答案 17 :(得分:0)

字符串状态下的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
       }

    },

答案 18 :(得分:-1)

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

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

..

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