Vue3.0中的reactive
阿新 • • 發佈:2020-12-14
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)。