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>

Relaterte artikler