vue3 - 使用reactive定義響應式資料進行資料修改賦值時,資料更新但檢視不更新

小那發表於2024-06-24

問題:

在uniapp-vue3的專案中,使用reactive定義了一個陣列,之後使用foreach對item的某個屬性進行重新賦值,但經過console資料顯示已經賦上值了,但是檢視一直不更新,包括嘗試nextTick(()=>{})和internalInstance.ctx.$forceUpdate()方法都無效。

分析:

檢視了官網文件,發現了這裡(響應式基礎 | Vue.js (vuejs.org)),注意第二條

reactive函式會返回一個Proxy包裝的物件,所以直接賦值一個陣列時會使定義的變數失去響應式。

let userInfo = reactive([{name:'hanmeimei',age:12}])
console.log(userInfo) // Proxy(Array) 列印出來是一個Proxy物件 當然具備響應式 
userInfo =[{name:'zhangsan',age:18},{name:'lisi,age:10}]// 直接後端資料進行賦值
console.log(userInfo)  //[{name:'zhangsan',age:18},{name:'lisi,age:10}] 可以看出 就是列印出了一個普通的陣列 所以不具備響應式

所以對於reactive建立的響應式資料應該避免直接使用=號進行賦值;會覆蓋響應式;

解決方案:

1、在封裝一層資料,例如:

<script setup>
import { reactive, ref } from "vue";
// 定義響應式 
let choosenList = reactive({list:[]});
// 請求的資料
let newList1 = [
  { name: "Eula", age: "18", isActive: false },
  { name: "Umbra", age: "17", isActive: false },
]
// 更改資料
const setList = () => {
  choosenList.list= newList1
}
</script>

2、使用陣列的splice來直接更改原陣列

還是用reactive來定義響應式資料,只不過改資料的方式變了,使用陣列的原生方法splice()來更改原陣列,不是直接覆蓋所以並不會影響響應式;

可改變原陣列的原生方法還有push、unshift、pop、shift、reverse、sort、splice、fill

<script setup>
import { reactive, ref } from "vue";
// 定義響應式 
let list1 = reactive([]);

// 請求的資料
let newList1 = [
  { name: "Eula", age: "18", isActive: false },
  { name: "Umbra", age: "17", isActive: false },
]

// 更改資料
const setList1 = () => {
  // splice三個引數時 第一項是起始索引  第二項是長度  第三項是新插入的元素,可以有多個
  list1.splice(0,list1.length,...newList1)
}
</script>

3、使用 ref 來定義資料

複雜資料型別也可以使用ref進行定義,而且資料都是響應式的;原理就有點像第一種方式,重新包裝了一層value;每次使用的時候都要寫.value;

ref實際就是對一個普通值做了一層包裝,包裝成一個物件,並透過其get和set實現依賴收集和更新,其實現原理類似於computed;

<script setup>
import { reactive, ref } from "vue";
// 定義響應式
let list1 = ref([]);

// 請求的資料
let newList1 = [
  { name: "Eula", age: "18", isActive: false },
  { name: "Umbra", age: "17", isActive: false },
]

// 更改資料
const setList1 = () => {
  list1.value = newList1;
}
</script>

let userInfo =reactive([{name:'Eula'}])

相關文章