typescript - Hvorfor fungerer vanlige konstanter fortsatt i Composition API (Vue 3)?
Som angitt i den offisielle dokumentasjonen, når vi definerer vår "data"-variabel i den nye composition API-setup-metoden, må vi bruke ref eller reactive for å la Vue holde oversikt over enhver endring på den spesifikke variabelen.
Jeg eksperimenterer med reaktivitet, og jeg har funnet en merkelig oppførsel. Ta denne komponenten som referanse:
App.vue
<template>
<div id="app">
<p>{{ awesomeState.txt }}</p>
<p>{{ myConst }}</p>
<button @click="operate">Test it</button>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import awesomeStore from "@/AwesomeStore";
export default defineComponent({
setup() {
const awesomeState = awesomeStore.getState();
const myConst = "I'm a const"; // This should be const `myConst = ref('...');`
return {
awesomeState,
myConst
};
},
name: "App",
methods: {
operate() {
this.myConst = 'Why this updates?';
awesomeStore.changeText("yess!");
}
}
});
</script>
AwesomeStore.ts
import { reactive, readonly, watch } from "vue";
export abstract class Store<T extends Record<string, any>> {
protected state: T;
constructor() {
const data = this.data();
this.state = reactive(data) as T;
watch(() => this.state, (value) => {
console.log(value); debugger;
}, {deep: true});
}
protected abstract data(): T;
public getState(): T {
return readonly(this.state) as T;
}
}
interface Test extends Object {
txt: string;
}
class AwesomeClass extends Store<Test> {
protected data(): Test {
return {
txt: "init"
};
}
public changeText(msg: string) {
this.state.txt = msg;
}
}
export default new AwesomeClass();
Når jeg klikker på knappen, blir egenskapen myConst oppdatert. Siden jeg ikke burde definere en metode utenfor grensene til setup(), forstår jeg ikke hvorfor dette skjer.
Kan noen få et hint?
Takk på forhånd,
OPPDATERING
Jeg glemte å nevne, den eksponerte oppførselen skjer bare hvis jeg prøver å endre konstanten samtidig med awesomeStore.changeText-metoden:
operate() {
this.myConst = 'Why this updates?';
//awesomeStore.changeText("yess!"); <-- If commented, myConst do not update.
}
Svar #1
Det er to ting som skjer her som gjør at det fungerer
1) du bruker en metode i stedet for å sende en funksjon
Du kan bruke den standard Vue API data:, methods:, osv... eller komposisjons-APIen, f.eks.: setup()
Ditt eksempel bruker begge. Så vidt jeg vet er det greit å gjøre dette, men vær oppmerksom på at en metode som gis gjennom setup versus methods vil oppføre seg forskjellig. I en metode vil du ha tilgang til this-objektet der myConst er muterbar
methods: {
operate() {
this.myConst = 'Why this updates?'; // <=== access to mutable variable in `this`
awesomeStore.changeText("yess!");
}
}
hvis du skulle bruke dette eksemplet (nedenfor) ville ikke oppdatering av myConst fungere
setup(){
const myConst = "I'm a const"; // This should be const `myConst = ref('...');`
// ...stuff...
return {
awesomeState,
myConst,
operate: ()=>{
this.myConst = 'Why this updates?'; // <=== nope
myConst = 'Why this updates?'; // <=== also nope
awesomeStore.changeText("yess!");
}
}
}
2) Du oppdaterer ref og static
Det andre problemet er at du oppdaterer den statiske verdien etterfulgt av referansen. Å endre referansen vil utløse ny gjengivelse, på det tidspunktet vil den statiske verdien ha endret seg
så hvis du fjerner oppdateringen gjennom butikken, bør du ikke se at oppdateringen skjer lenger
methods: {
operate() {
this.myConst = 'Why this updates?';
// awesomeStore.changeText("yess!"); // <== no ref change, no update
}
}
her er en lekeplass for å teste min "teori"
const {
createApp,
ref,
} = Vue
createApp({
el: '#app',
setup() {
let mystatic = 1
const myref = ref(1)
return {
mystatic,
myref,
updateStatic: () => {
mystatic++
},
updateRef: () => {
myref.value++
}
}
},
methods: {
updateStaticMethod() {
this.mystatic++
}
}
}).mount('#app')<script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
<div id="app">
<li>Static: {{ mystatic }}</li>
<li>Ref: {{ myref }}</li>
<li><button @click="updateStatic">Static+</button> will not change. ever.</li>
<li><button @click="updateStaticMethod">Static+(method)</button> will not update unless triggered elswhere</li>
<li><button @click="updateRef">Ref+</button>update ref value (and force redraw)</li>
<li><button @click="()=>{updateStaticMethod();updateRef();}">Both++</button> update both</li>
</div>