Vyhledávání na webu

javascript - Jak sledovat hodnoty ve store z vuex?


Používám vuex a vuejs 2 společně.

Jsem nový v vuex, chci sledovat změnu proměnné store.

Chci přidat funkci watch do mého vue komponentu

Toto je to, co mám zatím:

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

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

Chci vědět, jestli došlo k nějakým změnám v my_state

Jak mohu sledovat store.my_state ve své komponentě Vue.js?

Odpověď č. 1

Řekněme například, že máte koš s ovocem, a pokaždé, když přidáte nebo odeberete ovoce z koše, chcete (1) zobrazit informace o počtu ovoce, ale také (2) chcete být informováni o počtu ovoce nějakým stylovým způsobem...

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>

Vezměte prosím na vědomí, že název funkce v objektu watch se musí shodovat s názvem funkce v objektu computed. V uvedeném příkladu je název count.

Nové a staré hodnoty sledované vlastnosti budou předány do zpětného volání watch (funkce count) jako parametry.

Obchod s koši by mohl vypadat takto:

koš-na-ovoce.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

Další informace si můžete přečíst v následujících zdrojích:

  • Vypočítané vlastnosti a pozorovatelé
  • Dokumentace API: vypočítáno
  • Dokumentace API: sledovat

Odpověď č. 2

Je to tak jednoduché jako:

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

Pokud je obchod v modulu, použijte:

'$store.state.myModule.drawer'

Pro vnořené soubory použijte:

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

Odpověď č. 3

Neměli byste používat watchery komponent k poslechu změn stavu. Doporučuji použít getter funkce a poté je namapovat uvnitř vaší komponenty.

import { mapGetters } from 'vuex'

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

Ve vašem obchodě:

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

Měli byste být schopni poslouchat jakékoliv změny provedené ve vašem obchodě pomocí this.myState ve vaší komponentě.

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

Odpověď č. 4

Jak bylo zmíněno výše, není dobrý nápad sledovat změny přímo ve store

Ale v některých velmi vzácných případech to může být pro někoho užitečné, takže tuto odpověď nechám. Pro ostatní případy prosím podívejte se na odpověď @gabriel-robert

Můžete to udělat prostřednictvím state.$watch. Přidejte to do své metody created (nebo tam, kde potřebujete, aby se to provedlo) v komponentě

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

Více informací: https://vuex.vuejs.org/api/#watch

Odpověď č. 5

Myslím, že tazatel chce použít watch s Vuexem.

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

      },
      {
        deep:true
      }
      );

Odpověď č. 6

Tohle je pro všechny lidi, kteří nemohou vyřešit svůj problém pomocí getters a opravdu potřebují watcher, například pro komunikaci s ne-vue třetími stranami (viz Vue Watchers o tom, kdy používat watchery).

Sledující funkce a vypočítané hodnoty komponenty Vue také fungují na vypočítaných hodnotách. Takže u vuex to není jinak:

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

pokud jde jen o kombinování lokálního a globálního stavu, dokumentace k mapState poskytuje také příklad:

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

Odpověď č. 7

Zkoušel jsem doslova všechno, abych to uvedl do provozu.

Teorie

Zjistil jsem, že z nějakého důvodu změny objektů z $store nemusí nutně spustit metodu .watch. Moje dočasné řešení bylo

  • Obchod

    • Vytvořte složitou datovou sadu, která by měla, ale není schopna šířit změny do komponenty
    • Vytvořte inkrementující čítač ve state, který bude fungovat jako příznak a skutečně propaguje změny do komponenty, když je sledován
    • Vytvořte metodu v $store.mutators pro úpravu složitého datasetu a zvýšení počítacího signálu
  • Komponenta

    • Sledujte změny v příznaku $store.state. Když je změna zachycena, aktualizujte lokálně relevantní reaktivní změny z komplexního datového souboru $store.state
    • Proveďte změny v datasetu $store.state pomocí naší metody $store.mutators

Implementace

To je implementováno nějak takto:

Obchod

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

Součást

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

Spustitelná ukázka

Je to složité, ale v zásadě zde sledujeme změnu příznaku a poté aktualizujeme místní data, aby odrážela důležité změny v objektu, který je uložen v $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/[email "></script>
<script src="https://unpkg.com/[email /dist/vuex.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email /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>

Odpověď č. 8

pokud používáte TypeScript, můžete:

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

..

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

Odpověď č. 9

Pokud chcete jednoduše sledovat stavovou vlastnost a pak na změny této vlastnosti v komponentě podle toho reagovat, podívejte se na níže uvedený příklad.

V store.js:

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

V tomto scénáři vytvářím stavovou vlastnost boolean, kterou budu měnit na různých místech v aplikaci takto:

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

Nyní, pokud potřebuji sledovat tuto stavovou vlastnost v nějaké jiné komponentě a poté změnit místní vlastnost, napsal bych následující v háku mounted:

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

Nejprve nastavím pozorovatele na vlastnost stavu a poté v callback funkci používám value této vlastnosti ke změně localProperty.

Doufám, že to pomůže!

Související články