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.mutatorspro ú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
$store.state pomocí naší metody $store.mutatorsImplementace
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!
