为什么普通常量在 Composition API (Vue 3) 中仍然有效?
Why plain constant still works in Composition API (Vue 3)?
如官方documentation所述,在新的组合api setup
方法中定义我们的“数据”变量时,我们必须使用ref
或reactive
以便让 Vue 跟踪该特定变量的任何更改。
我正在试验反应性,我发现了一个奇怪的行为。
以这个组件这个组件为参考:
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();
当我单击该按钮时,属性 myConst
会更新。
除了我不应该在 setup()
的边界之外定义方法,我不明白为什么会这样。
谁能得到提示?
提前致谢,
更新
我忘了说,只有当我尝试使用 awesomeStore.changeText
方法修改常量时才会发生暴露的行为:
operate() {
this.myConst = 'Why this updates?';
//awesomeStore.changeText("yess!"); <-- If commented, myConst do not update.
}
这里发生了两件事使它起作用
1) 您正在使用方法而不是传递函数
您可以使用标准 Vue API data:, methods:,etc...
或组合 API 即:setup()
您的示例同时使用了两者。 AFAIK,这样做是可以的,但是请注意 setup
与 methods
传递的方法会有不同的行为。在一个方法中,您将有权访问 this
对象,其中 myConst
是可变的
methods: {
operate() {
this.myConst = 'Why this updates?'; // <=== access to mutable variable in `this`
awesomeStore.changeText("yess!");
}
}
如果您要使用此示例(如下),更新 myConst
将不起作用
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) 您正在更新 ref 和 static
另一个问题是您正在更新静态值,然后是引用。更改 ref 将 re-trigger 呈现,此时静态值会更改
因此,如果您通过商店删除更新,您应该不会再看到更新发生了
methods: {
operate() {
this.myConst = 'Why this updates?';
// awesomeStore.changeText("yess!"); // <== no ref change, no update
}
}
这里是测试我“理论”的游乐场
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>
如官方documentation所述,在新的组合api setup
方法中定义我们的“数据”变量时,我们必须使用ref
或reactive
以便让 Vue 跟踪该特定变量的任何更改。
我正在试验反应性,我发现了一个奇怪的行为。 以这个组件这个组件为参考:
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();
当我单击该按钮时,属性 myConst
会更新。
除了我不应该在 setup()
的边界之外定义方法,我不明白为什么会这样。
谁能得到提示?
提前致谢,
更新
我忘了说,只有当我尝试使用 awesomeStore.changeText
方法修改常量时才会发生暴露的行为:
operate() {
this.myConst = 'Why this updates?';
//awesomeStore.changeText("yess!"); <-- If commented, myConst do not update.
}
这里发生了两件事使它起作用
1) 您正在使用方法而不是传递函数
您可以使用标准 Vue API data:, methods:,etc...
或组合 API 即:setup()
您的示例同时使用了两者。 AFAIK,这样做是可以的,但是请注意 setup
与 methods
传递的方法会有不同的行为。在一个方法中,您将有权访问 this
对象,其中 myConst
是可变的
methods: {
operate() {
this.myConst = 'Why this updates?'; // <=== access to mutable variable in `this`
awesomeStore.changeText("yess!");
}
}
如果您要使用此示例(如下),更新 myConst
将不起作用
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) 您正在更新 ref 和 static
另一个问题是您正在更新静态值,然后是引用。更改 ref 将 re-trigger 呈现,此时静态值会更改
因此,如果您通过商店删除更新,您应该不会再看到更新发生了
methods: {
operate() {
this.myConst = 'Why this updates?';
// awesomeStore.changeText("yess!"); // <== no ref change, no update
}
}
这里是测试我“理论”的游乐场
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>