reactive()--定義響應式數據
reactive()
接受一個對象,包括json數據和數組都可以,返回一個對象的響應式代理(Proxy
對象)。
<script src="https://unpkg.com/vue@next"></script>
<div id="Application">
</div>
<script>
const App = Vue.createApp({
//進行組件數據初始化
setup() {
//數據
//基本類型使用ref,引用類型使用reactive
//增刪改查都可以操作。
//內部是通過Proxy代理的形式
let myData = Vue.reactive({
value: 0
})
//按鈕的單擊方法
function click() {
myData.value += 1
console.log(myData.value)
}
//數據返回
return {
myData,
click
}
},
//模板中可以直接使用setup方法中定義的數據和函數
template: `
<h1>測試數據:{{ myData.value }}</h1>
<button @click="click">點擊</button>
`
})
App.mount("#Application")
</script>
您可以打開瀏覽器控制臺,觀察控制臺的打印數據
- eactive 是 Vue3 中提供的實現響應式數據的方法。
- 在 Vue2 中響應式數據是通過 defineProperty 來實現的,
- 在 Vue3 中響應式數據是通過 ES6 的 Proxy來實現的。
- reactive 參數必須是對象 (json / arr)
- 如果給 reactive 傳遞了其它對象
- 默認情況下,修改對象無法實現界面的數據綁定更新。
- 如果需要更新,需要進行重新賦值。(即不允許直接操作數據,需要放個新的數據來替代原數據)
在 reactive 使用基本類型參數
基本類型(數字、字符串、布爾值)在 reactive 中無法被創建成 proxy 對象,也就無法實現監聽。
<script src="https://unpkg.com/vue@next"></script>
<div id="Application">
</div>
<script>
const App = Vue.createApp({
setup() {
let msg = Vue.reactive(0)
function click() {
console.log(msg);
msg++;
}
return {
msg,
click
};
},
template: `
<h1>測試數據:{{ msg }}</h1>
<button @click="click">點擊</button>
`
})
App.mount("#Application")
</script>
點擊 按鈕 ,我們期望的結果是數字從 0 變成 1,然而實際上界面上的數字并沒有發生任何改變。
查看控制臺,它的輸出是這樣的(我點了 3 次)(您可以嘗試F12打開控制臺實時觀察效果)
1
2
3
出現提示
value cannot be made reactive: 0
而輸出的值確實發生了變化,只不過這種變化并沒有反饋到界面上,也就是說并沒有實現雙向數據綁定。當然,如果是 ref 的話,就不存在這樣的問題。
而如果要使用 reactive ,我們需要將參數從 基本類型 轉化為 對象。
<script src="https://unpkg.com/vue@next"></script>
<div id="Application">
</div>
<script>
const App = Vue.createApp({
setup() {
let msg = Vue.reactive({ value: 0 })
function click() {
console.log(msg);
msg.value++;
}
return {
msg,
click
};
},
template: `
<h1>測試數據:{{ msg.value }}</h1>
<button @click="click">點擊</button>
`
})
App.mount("#Application")
</script>
將參數替換成了對象?{num: 0}
,此時,點擊按鈕界面就會產生改變(我點了 3 次)。
控制臺打印消息(您可以在本頁點擊按鈕,觀察控制臺變化)
Proxy?{value: 0}
[[Handler]]: Object
[[Target]]: Object
[[IsRevoked]]: false
Proxy?{value: 1}
Proxy?{value: 2}
可以看到,msg
?成功被創建成了?proxy
?對象,
他通過劫持對象的?get
?和?set
?方法實現了對象的雙向數據綁定。
對象內部變化
深層的、對象內部的變化也能被察覺到(注意下面代碼中的?inner
?)
<script src="https://unpkg.com/vue@next"></script>
<div id="Application">
</div>
<script>
const App = Vue.createApp({
setup() {
let msg = Vue.reactive({
value: {
inner: 0
}
})
function click() {
console.log(msg);
msg.value.inner++;
}
return {
msg,
click
};
},
template: `
<h1>測試數據:{{ msg.value.inner }}</h1>
<button @click="click">點擊</button>
`
})
App.mount("#Application")
</script>
可點擊按鈕,打開瀏覽器控制臺觀察變化
數組變化
<script src="https://unpkg.com/vue@next"></script>
<div id="Application">
</div>
<script>
const App = Vue.createApp({
setup() {
let msg = Vue.reactive([1, 2, 3])
function click() {
console.log(msg);
msg[0] += 1;
msg[1] = 5;
}
return {
msg,
click
};
},
template: `
<h1>測試數據:{{ msg }}</h1>
<button @click="click">點擊</button>
`
})
App.mount("#Application")
</script>
可點擊按鈕,打開瀏覽器控制臺觀察變化
重新賦值
在?reactive
?使用?Date
?參數
如果參數不是數組、對象,而是稍微奇怪一點的數據類型,例如說?Date
,我們需要重新賦值
<script src="https://unpkg.com/vue@next"></script>
<div id="Application">
</div>
<script>
const App = Vue.createApp({
setup() {
let msg = Vue.reactive({
date: new Date()
})
function click() {
console.log("第一次打印", msg);
msg.date.setDate((msg.date.getDate() + 1));
msg.date = new Date(msg.date);
console.log("第二次打印", msg)
}
return {
msg,
click
};
},
template: `
<h1>測試數據:{{ msg.date }}</h1>
<button @click="click">點擊</button>
`
})
App.mount("#Application")
</script>
這里我采用了拷貝的方案重新賦值了?msg.date
,界面成功發生了變化(日期 + 1)。
響應式代理 vs. 原始對象
值得注意的是,reactive()
?返回的是一個源對象的?Proxy,它和源對象是不相等的:
const raw = {}
const proxy = reactive(raw)
// 代理和原始對象不是全等的
console.log(proxy === raw) // false
只有代理是響應式的,更改原始的對象不會觸發更新。因此,使用 Vue 的響應式系統的最佳實踐是 僅使用代理作為狀態。
為保證訪問代理的一致性,對同一個對象調用 reactive() 會總是返回同樣的代理,而對代理調用 reactive() 則會返回它自己:
// 在同一個對象上調用 reactive() 會返回相同的代理
console.log(reactive(raw) === proxy) // true
// 在一個代理上調用 reactive() 會返回它自己
console.log(reactive(proxy) === proxy) // true
這個規則對深層級的對象也適用。依靠深層響應性,響應式對象內的深層級對象依然是代理:
const proxy = reactive({})
const raw = {}
proxy.nested = raw
console.log(proxy.nested === raw) // false