Vue3.0中的reactive
reactive
是 Vue3 中提供的實現響應式數據的方法。- 在 Vue2 中響應式數據是通過 defineProperty 來實現的,
- 在 Vue3 中響應式數據是通過 ES6 的
Proxy
來實現的。 - reactive 參數必須是對象 (json / arr)
- 如果給 reactive 傳遞了其它對象
- 默認情況下,修改對象無法實現界面的數據綁定更新。
- 如果需要更新,需要進行重新賦值。(即不允許直接操作數據,需要放個新的數據來替代原數據)
在 reactive
使用基本類型參數
基本類型(數字、字符串、布爾值)在 reactive
中無法被創建成 proxy
對象,也就無法實現監聽。
<template>
<div>
<p>{{msg}}</p>
<button @click="c">button</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let msg = reactive(0)
function c() {
console.log(msg);
msg ++;
}
return {
msg,
c
};
}
}
</script>
點擊 button ,我們期望的結果是數字從 0 變成 1,然而實際上界面上的數字並沒有發生任何改變。
查看控制台,它的輸出是這樣的(我點了 3 次)
出現提示
value cannot be made reactive: 0
而輸出的值確實發生了變化,只不過這種變化並沒有反饋到界面上,也就是說並沒有實現雙向數據綁定。當然,如果是 ref
的話,就不存在這樣的問題。而如果要使用 reactive
,我們需要將參數從 基本類型 轉化為 對象。
<template>
<div>
<p>{{msg.num}}</p>
<button @click="c">button</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let msg = reactive({
num: 0
})
function c() {
console.log(msg);
msg.num ++;
}
return {
msg,
c
};
}
}
</script>
將參數替換成了對象 {num: 0}
,此時,點擊按鈕界面就會產生改變(我點了 3 次)。
在控制台打印消息
可以看到,msg
成功被創建成了 proxy
對象,他通過劫持對象的 get
和 set
方法實現了對象的雙向數據綁定。
深層的、對象內部的變化也能被察覺到(注意下面代碼中的 inner
)
<template>
<div>
<p>{{msg.num.inner}}</p>
<button @click="c">button</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let msg = reactive({
num: {
inner: 0
}
})
function c() {
console.log(msg);
msg.num.inner ++;
}
return {
msg,
c
};
}
}
</script>
數組變化也不在話下。
<template>
<div>
<p>{{msg}}</p>
<button @click="c">button</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let msg = reactive([1, 2, 3])
function c() {
console.log(msg);
msg[0] += 1;
msg[1] = 5;
}
return {
msg,
c
};
}
}
</script>
在-reactive-使用-date-參數在 reactive
使用 Date
參數
如果參數不是數組、對象,而是稍微奇怪一點的數據類型,例如說 Date
,那么麻煩又來了。
<template>
<div>
<p>{{msg}}</p>
<button @click="c">button</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let msg = reactive(new Date())
function c() {
console.log(msg);
msg.setDate(msg.getDate() + 1);
console.log(msg);
}
return {
msg,
c
};
}
}
</script>!
這里我先打印了 msg
兩次,可以看到,點擊一次 button ,msg
的數據是存在變化的,但界面並未發生變化,同時我們發現在控制台里,msg
並未被識別成 proxy
。
就算我們把 Date
放在對象里,就像這樣
<template>
<div>
<p>{{msg.date}}</p>
<button @click="c">button</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let msg = reactive({
date: new Date()
});
function c() {
console.log(msg);
msg.date.setDate(msg.date.getDate() + 1);
console.log(msg);
}
return {
msg,
c
};
}
}
</script>
也仍然不起效果。
顯然,對於這種數據類型,我們需要做特殊處理。
這個特殊處理就是重新賦值(,而不是直接修改原來的值)。
<template>
<div>
<p>{{msg.date}}</p>
<button @click="c">button</button>
</div>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
let msg = reactive({
date: new Date()
});
function c() {
console.log(msg);
msg.date.setDate((msg.date.getDate() + 1));
msg.date = new Date(msg.date);
console.log(msg);
}
return {
msg,
c
};
}
}
</script>
這里我采用了拷貝的方案重新賦值了 msg.date
,界面成功發生了變化(日期 + 1)。