vue3.0 Reactive數據更新頁面沒有刷新的問題
vue3.0 Reactive數據更新頁面沒有刷新
vue 3.0 ref 和 Reactive 數據響應式,以及使用 Reactive 數據已更新但頁面沒有同步刷新異常
Vue 3.0 中我們使用 reactive() 定義的響應式數據的時候,當我們對象再次賦值,我們發現數據已經修改成功,但是頁⾯並沒有自動渲染成最新的數據;
這時我們可以改成 ref () 或者對 reactive() 綁定的數據類型下點功夫;
- ref()
ref() 接受一個內部值並返回一個響應式且可變的 ref 對象。ref 對象僅有一個 .value property,指向該內部值
<template> <div> <button @click="changeMsg">更改數據</button> <div>{{ message }}</div> </div> </template> <script setup lang="ts"> import {ref} from 'vue' /** * ref() 基礎用法 */ let message = ref<string | number>("測試數據") /** * 更改 ref 數據 */ const changeMsg = () => { message.value = "更改測試數據" } </script>
- reactive()
reactive() 主要時用來綁定一些復雜的數據類型,比如(對象、數組) ;它不可以綁定普通的數據類型,否則會報錯;如果我們需要綁定普通的數據類型,建議使用上面的 ref()
<template> <div> <button @click="changeObj">更改數據</button> <div> {{obj.data}} </div> <div> {{obj.dataBoolean}} </div> <div> {{obj.dataArr}} </div> </div> </template> <script setup lang="ts"> import {reactive} from 'vue' /** * reactive() 基礎用法 */ const obj = reactive({ data: '', dataBoolean: false, dataArr: <number[]>[], }) /** * 更改 reactive() 數據 */ const changeObj = () => { obj .data = '測試數據' obj .dataBoolean = true obj .dataArr = [1, 2, 3, 4, 5, 6] } </script>
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)。
響應式代理 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
總結
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。