309

I am using vuex and vuejs 2 together.

I am new to vuex, I want to watch a store variable change.

I want to add the watch function in my vue component

This is what I have so far:

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

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

I want to know if there are any changes in the my_state

How do I watch store.my_state in my vuejs component?

leonheess
  • 16,068
  • 14
  • 77
  • 112
raffffffff
  • 3,447
  • 4
  • 16
  • 15

22 Answers22

350

Let's say, for example, that you have a basket of fruits, and each time you add or remove a fruit from the basket, you want to (1) display info about fruit count, but you also (2) want to be notified of the count of the fruits in some fancy fashion...

fruit-count-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, yay!`)
    }
  }
}
</script>

Please note, that the name of the function in the watch object, must match the name of the function in the computed object. In the example above the name is count.

New and old values of a watched property will be passed into watch callback (the count function) as parameters.

The basket store could look like this:

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

You can read more in the following resources:

tony19
  • 125,647
  • 18
  • 229
  • 307
Anastazy
  • 4,624
  • 2
  • 13
  • 22
  • I am just wondering what shoul I do when the `watch` action should split into two steps: 1) First, checking if the the desire data is cached and if it does just return the cached data; 2) If the cache failed I need an async ajax action to fetch the data, but this seems to be the `action`'s work. Hoping my question make sense, thank you! – 1Cr18Ni9 Aug 06 '19 at 10:17
  • 2
    What is the benefit of this, over micah5's answer, which just sets a watcher in the component, on the store value? It has less code to maintain. – Exocentric May 04 '20 at 05:02
  • 1
    @Exocentric When I written the answer, question was not clear for me. There is no context why it is needed to watch properties. Think of it like: "I want to watch variable X, so I can do Y." Probably that is why most answers propose so vastly different approaches. No one knows what the intent is. That is why I included "objectives" in my answer. If you have different objectives, different answer might fit them. My example is just a starting point for experimentation. It is not meant to be a plug & play solution. There is no "benefit", because benefits depends on your situation. – Anastazy May 06 '20 at 09:28
  • @1Cr18Ni9 I think caching does not belong in component code. You will end up over-engineering something that should be really simple (fetching data and binding it to the view). Caching is already implemented in the browser. You can take advantage of it by sending correct headers from server. Simple explanation here: https://csswizardry.com/2019/03/cache-control-for-civilians/. You can also take a look at ServiceWorkers which allow for website to work even without internet connection. – Anastazy May 06 '20 at 11:15
  • Why do you have to watch the computed value? Why does the computed value not create a working watch for this value? That is after all the point of a computed value. – geoidesic Nov 25 '20 at 07:46
267

It's as simple as:

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

If the store is in a module, use:

'$store.state.myModule.drawer'

For nested files, use:

'$store.state.fileOne.fileTwo.myModule.drawer'
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
mic
  • 4,300
  • 1
  • 19
  • 25
  • 2
    Would be even simplier if it was `function(n) { console.log(n); }` – WofWca Feb 17 '20 at 09:57
  • 2
    Interestingly, I first wrote `'this.$store.state.something'` and it didn't work so I assumed this wouldn't work... Didn't know that you need to leave out the `this` part! Could somebody explain it? I guess watchers already assume you're working on the Vue instance so `this` is unnecessary? – xji Oct 04 '20 at 22:32
  • 17
    By the way, if the store is namespaced with modules, just write `'$store.state.module.something'` – xji Oct 04 '20 at 22:32
  • how would I do it if I want to watch state in a nested vuex folder like `store/fileOne/fileTwo/fileThree/stateFile` ? @xji – seyet Dec 01 '21 at 05:38
  • 2
    @seyet just use '$store.state.fileOne.fileTwo.fileThree.stateFile.yourState' – Do Trung Duc Dec 14 '21 at 07:40
74

You should not use component's watchers to listen to state change. I recommend you to use getters functions and then map them inside your component.

import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters({
      myState: 'getMyState'
    })
  }
}

In your store:

const getters = {
  getMyState: state => state.my_state
}

You should be able to listen to any changes made to your store by using this.myState in your component.

https://vuex.vuejs.org/en/getters.html#the-mapgetters-helper

smunk
  • 314
  • 3
  • 8
Gabriel Robert
  • 3,012
  • 2
  • 18
  • 36
  • 2
    I don't know how to implement mapGetters. Can you point me to an example. It would be a big help. I just implement GONG answer at the moment. TY – Rbex May 15 '17 at 06:27
  • 2
    @Rbex "mapGetters" is part of 'vuex' library. You don't need to implement it. – Gabriel Robert May 16 '17 at 15:07
  • Thanks, I've seen videos in vuex and I have already used vuex mapGetters `computed: { ...mapGetters({ myState: 'getMyState' }) }` that is the part that gives me error and I install babel. Now it works like a charm... TY – Rbex May 16 '17 at 21:44
  • This works great along with vue-highcharts to provide real time moving chart. – PrestonDocks Jan 14 '18 at 17:15
  • @Gabriel Robert Maybe you can help me. Look at this : https://stackoverflow.com/questions/49487276/how-can-i-send-data-from-parent-to-child-component-by-vuex-store-in-vue-componen – moses toh Mar 26 '18 at 08:52
  • 135
    This answer is just wrong. He actually needs to watch the computed properties. – chesscov77 May 23 '18 at 01:09
  • 19
    The getter once called will only retrieve the state at that time. If you want that property to reflect the state change from another component you have to watch it. – C Tierney Jun 02 '18 at 12:23
  • 5
    Why "You should not use component's watchers to listen to state change"? Here is example you might not think of, if I want to watch on token from the state, and when it change to redirect to another page. so, there is some cases you need to do that. maybe you need more experience to know that. – Shlomi Levi Sep 29 '18 at 16:28
  • 2
    This isn't enough. You must WATCH it in this case. – Rory May 07 '19 at 13:30
59

As mentioned above it is not good idea to watch changes directly in store

But in some very rare cases it may be useful for someone, so i will leave this answer. For others cases, please see @gabriel-robert answer

You can do this through state.$watch. Add this in your created (or where u need this to be executed) method in component

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

More details: https://vuex.vuejs.org/api/#watch

Nic Scozzaro
  • 6,651
  • 3
  • 42
  • 46
GONG
  • 3,976
  • 1
  • 24
  • 27
  • 3
    I don't think it's a good idea to watch state directly. We should use getters. https://vuex.vuejs.org/en/getters.html#the-mapgetters-helper – Gabriel Robert Apr 08 '17 at 12:51
  • 15
    @GabrielRobert I think there's a place for both. If you need to reactively change template conditions based, using a computed value with mapState, etc makes sense. But otherwise, like for even flow control in a component, you need a full watch. You are right, you should not use plain component watchers, but the state.$watch is designed for these use cases – roberto tomás Aug 31 '17 at 20:10
  • 20
    Everyone mentions it, but no one says why! I'm trying to build a vuex store that's auto-synchronised with a DB upon changes. I feel watchers on the store is the most frictionless way! What do you think? Still not a good idea? – mesqueeb Jun 21 '18 at 02:12
22

I think the asker wants to use watch with Vuex.

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

      },
      {
        deep:true
      }
      );
yeahdixon
  • 6,647
  • 1
  • 41
  • 43
19

This is for all the people that cannot solve their problem with getters and actually really need a watcher, e.g. to talk to non-vue third party stuff (see Vue Watchers on when to use watchers).

Vue component's watchers and computed values both also work on computed values. So it's no different with 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);
        }
    }
}

if it's only about combining local and global state, the mapState's doc also provides an example:

computed: {
    ...mapState({
        // to access local state with `this`, a normal function must be used
        countPlusLocalState (state) {
          return state.count + this.localCount
        }
    }
})
tony19
  • 125,647
  • 18
  • 229
  • 307
dube
  • 4,898
  • 2
  • 23
  • 41
14

I tried literally everything to get this working.

Theory

I found that for some reason, changes to objects from $store don't necessarily trigger a .watch method. My workaround was to

  • Store
    • Create a complex data set which should but doesn't propagate changes to a Component
    • Create an incrementing counter in the state to act as a flag, which does propagate changes to a Component when watched
    • Create a method in $store.mutators to alter the complex dataset and increment the counter flag
  • Component
    • Watch for changes in the $store.state flag. When change is detected, update locally relevant reactive changes from the $store.state complex data set
    • Make changes to the $store.state's dataset using our $store.mutators method

Implementation

This is implemented something like this:

Store

let store = Vuex.Store({
  state: {
    counter: 0,
    data: { someKey: 0 }
  },
  mutations: {
    updateSomeKey(state, value) {
      update the state.data.someKey = value;
      state.counter++;
    }
  }
});

Component

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

Runnable demo

It's convoluted but basically here we are watching for a flag to change and then updating local data to reflect important changes in an object that's stored in the $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>
Adonis Gaitatzis
  • 3,189
  • 26
  • 24
  • 1
    You ran into the reactivity caveat of Vue, which is pretty well documented: Once observed, you can no longer add reactive properties to the root data object. It is therefore recommended to declare all root-level reactive properties upfront, before creating the instance. – Derek Pollard Oct 29 '20 at 15:06
  • Meaning, changing `votes[xxx]` where xxx is not defined upfront will not give you reactivity of those value changes – Derek Pollard Oct 29 '20 at 15:06
  • 1
    More information about this issue and how to move around it: https://vuejs.org/v2/guide/reactivity.html#For-Objects – Derek Pollard Oct 29 '20 at 15:10
  • @DerekPollard when I tried to use resolve this problem by creating a reactive component to manage the data as suggested in the docs you reference, I my project crashed with a **recursive loop counter exceeded**, which implies to me that the `$store.state`'s object is already reactive. Additionally, when I manually verified the `$store.state` data had changed *eg by button click*, the changes were reflected in the component, but this change didn't happen automatically. The solution above worked for me. I would love something more elegant. – Adonis Gaitatzis Oct 29 '20 at 16:35
  • 1
    The answer here is to use `Vue.set(state.votes, newVotesObject)` in your mutations – Derek Pollard Oct 29 '20 at 16:41
  • Here is a working example without the workarounds and a bit cleaner: https://codepen.io/d-pollard/pen/NWrYKme?editors=1010 – Derek Pollard Oct 29 '20 at 17:31
  • Another working example with dynamic options: https://codepen.io/d-pollard/pen/WNxzNbW?editors=1011 – Derek Pollard Oct 29 '20 at 17:53
  • @DerekPollard `Vue.set()` isn't always helpful, for instance if you happen to be importing non-reactive data into your Vuex state or into your Vue component. – Adonis Gaitatzis Dec 30 '20 at 18:15
13

if you use typescript then you can :

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

..

@Watch("$store.state.something")
private watchSomething() {
   // use this.$store.state.something for access
   ...
}
Zhang Sol
  • 149
  • 1
  • 4
  • Why exactly was this downvoted? Just because the solution is for vue-class-component and the TO was asking for old vue-class styles? I find the former preferable. Maybe @Zhang Sol could mention in the introduction, that this is explicitly for vue-class-component? – JackLeEmmerdeur Sep 16 '19 at 22:16
  • Note sure why a typescript decorator would be preferable to a vue native solution as simple as this one : https://stackoverflow.com/a/56461539/3652783 – yann_yinn Feb 19 '20 at 15:26
  • @yann_yinn well, because your example won't work with typescript component – Desprit Nov 05 '20 at 10:45
  • @Desprit true but the question was not using nor mentionning TypeScript. But still a useful tip for Typscript users for sure. – yann_yinn Nov 06 '20 at 11:51
13

If you simply want to watch a state property and then act within the component accordingly to the changes of that property then see the example below.

In store.js:

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

In this scenario, I am creating a boolean state property that I am going to change in different places in the application like so:

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

Now, if I need to watch that state property in some other component and then change the local property I would write the following in the mounted hook:

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

Firstly, I am setting a watcher on the state property and then in the callback function I use the value of that property to change the localProperty.

I hope it helps!

Jakub A Suplicki
  • 4,586
  • 1
  • 23
  • 31
7

The best way to watch store changes is to use mapGetters as Gabriel said. But there is a case when you can't do it through mapGetters e.g. you want to get something from store using parameter:

getters: {
  getTodoById: (state, getters) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }
}

in that case you can't use mapGetters. You may try to do something like this instead:

computed: {
    todoById() {
        return this.$store.getters.getTodoById(this.id)
    }
}

But unfortunately todoById will be updated only if this.id is changed

If you want you component update in such case use this.$store.watch solution provided by Gong. Or handle your component consciously and update this.id when you need to update todoById.

tony19
  • 125,647
  • 18
  • 229
  • 307
Arseniy-II
  • 8,323
  • 5
  • 24
  • 49
  • At least in my case which is slightly different `return this.$store.getters.getTodoById({id: this.id})` not sure if it's the object that causes this not to be reactive... but it's not reactive. – geoidesic Nov 25 '20 at 07:59
7

Create a Local state of your store variable by watching and setting on value changes. Such that the local variable changes for form-input v-model does not directly mutate the store variable.

data() {
  return {
    localState: null
  };
 },
 computed: {
  ...mapGetters({
    computedGlobalStateVariable: 'state/globalStateVariable'
  })
 },
 watch: {
  computedGlobalStateVariable: 'setLocalState'
 },
 methods: {
  setLocalState(value) {
   this.localState = Object.assign({}, value);
  }
 }
Mukundhan
  • 3,284
  • 23
  • 36
7

Use your getter in computed then watch it and do what you need

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

  }
Amir
  • 284
  • 1
  • 3
  • 7
6

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

alloyking
  • 341
  • 3
  • 10
  • You can fire this in the beforeMount() hook of your component then filter the incoming mutations with an if Statement. e.g if( mutation.type == "names/SET_NAMES") {... do something } – Alex Feb 04 '19 at 18:53
6

Inside the component, create a computed function

computed:{
  myState:function(){
    return this.$store.state.my_state; // return the state value in `my_state`
  }
}

Now the computed function name can be watched, like

watch:{
  myState:function(newVal,oldVal){
    // this function will trigger when ever the value of `my_state` changes
  }
}

The changes made in the vuex state my_state will reflect in the computed function myState and trigger the watch function.

If the state my_state is having nested data, then the handler option will help more

watch:{
  myState:{
    handler:function(newVal,oldVal){
      // this function will trigger when ever the value of `my_state` changes
    },
    deep:true
  }
}

This will watch all the nested values in the store my_state.

Rijosh
  • 1,538
  • 1
  • 8
  • 11
5

You can use a combination of Vuex actions, getters, computed properties and watchers to listen to changes on a Vuex state value.

HTML Code:

<div id="app" :style='style'>
  <input v-model='computedColor' type="text" placeholder='Background Color'>
</div>

JavaScript Code:

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

tony19
  • 125,647
  • 18
  • 229
  • 307
Amin NAIRI
  • 2,292
  • 21
  • 20
4

When you want to watch on state level, it can be done this way:

let App = new Vue({
    //...
    store,
    watch: {
        '$store.state.myState': function (newVal) {
            console.log(newVal);
            store.dispatch('handleMyStateChange');
        }
    },
    //...
});
Andy
  • 2,892
  • 2
  • 26
  • 33
  • It's not good idea to handle `store.state` change by `dispatch` state action from component as this behaviour only work if you use that component. Also you might ended with infinite loop. Watch to `store.state` change rarely use, for example if you have a component or a page that should do some action based on `store.state` changed that could not handled by using computed mapState only where you cannot compare `newValue` vs `oldValue` – Januartha Aug 31 '18 at 22:24
  • @Januartha what is your suggestion to this problem then? – Billal Begueradj Sep 04 '18 at 14:43
  • @Andy yes of course its work. I just want to note why you call `store.dispatch`? if you want to handle `store.state` change for `store' why not handle it inside `store.mutations` ? – Januartha Sep 04 '18 at 15:50
  • @BillalBEGUERADJ I prever **dube** solution is more cleaner – Januartha Sep 04 '18 at 15:54
  • @Januartha, because there might be an ajax call to happen before doing a mutation, that's why i use `store.dispatch` first. For example, i want to get all the cities from a country whenever `$store.state.country` changes, so i add this to the watcher. Then i would write an ajax call: in `store.dispatch('fetchCities')` i write: `axios.get('cities',{params:{country: state.country }}).then(response => store.commit('receiveCities',response) )` – Andy Sep 24 '18 at 10:29
1

Vue watch in string state

state:

$store.state.local_store.list_of_data

inside component

  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
       }

    },
Balaji
  • 9,657
  • 5
  • 47
  • 47
1

A very simple method in which I use computed is something like this. May be it is of any help to you.

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

Another version in which you can do this is

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

This is a format of accessing the getter from the store. Hope you have a great day.

kshitij
  • 642
  • 9
  • 17
0

You can also use mapState in your vue component to direct getting state from store.

In your component:

computed: mapState([
  'my_state'
])

Where my_state is a variable from the store.

Eugene Kulakov
  • 441
  • 3
  • 9
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: {}
})
semua bisa
  • 11
  • 2
  • 3
    Welcome to the site. Putting only a code snippet is not enough. Please provide some explanations about your code. – pgk Jan 27 '20 at 11:37
0

I used this way and it works:

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
}

And in your component where you use state from store:

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

When user submit form, action STORE will be call, after created success, CREATE_SUCCESS mutation is committed after that. Turn createSuccess is true, and in component, watcher will see value has changed and trigger notification.

isSuccess should be match with the name you declare in getters.js

Vuong Tran
  • 303
  • 5
  • 15
0

You can also watch it safely with debouncedWatch (vue use function)

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