1. 程式人生 > 其它 >vue3中當用reactive()中定義的物件再次賦值,頁面不會自動更新解決方法

vue3中當用reactive()中定義的物件再次賦值,頁面不會自動更新解決方法

在vue3裡,ref和reacitve都可以定義響應式資料,但是兩者有所不同。在使用reactive定義複雜結構的響應式資料時,如果你要對其賦值,會丟失其響應性。然後賦值是我們經常進行的操作,那麼該怎麼解決呢?

問題:reactive定義的資料不能直接賦值

下述程式碼會報錯: Cannot assign to "form" because it is a constant

//申明表單物件
const form = reactive({


id: undefined,
    name: undefined,
    ...
  })
//通過axios讀取資料
  getData(id).then((res) => {
        const { code, data } = res
        if (code == 200) {
          form = {             ...data,           }
        }
     })
   }

解決方法

1. 改為ref定義

const form= ref({})
form.value = {...data}

2. 如果是陣列的話,可以使用push新增資料

const arr = reactive([])
arr.push(...[1, 2, 3])

3.再封裝一層資料(推薦!)即定義屬性名,在後期賦值的時候,對屬性名進行賦值

const state = reactive({
  arr: [],
form:{} }); state.arr
= [1, 2, 3]

state.form = {...data}

但是這樣的話在html模板裡,使用資料就得state.arr
所以我們可以用解構將它return出來(script setup 裡面 不需要return 結構出來即可)

但是reactive解構出來的資料會丟失響應性
所以再用 toRefs()方法為它們新增響應性
最終為:

const state = reactive({
  arr: [],
  form:{}
}); 
state.arr
= [1, 2, 3]
state.form ={...data}
return{ ...toRefs(state), }

//如果是在 script setup 裡面 不需要return 結構出來即可

const { form,arr} = toRefs(state)
 

4.其他,參考下述轉載的方式

優雅的解決reactive()響應式物件初始化重新賦值問題

程式碼裡寫了注意點,此處也先宣告注意事項:

template 裡必須繫結的是 ref() 資料來源 !!

重新初始化整個響應式物件時,用來資料操作的實際變數(例子裡的info)也需要重新賦值!

這是vue3沒正式釋出解決 ref() `.value` 的語法糖的相對方案。正式敲定且釋出後應該就可廢棄我這方案了。

為什麼不用 Object.assign() 處理reactive()? 什麼情況下用 Object.assign() 處理reactive()?

Object.assign() 方法用於將所有可列舉屬性的值從一個或多個源物件分配(賦值)到目標物件。所以無法對例子裡新增加的資料newKey清除掉!(這種問題常見於從後端介面獲得的資料,有時候有{}值,有時候null)。此時不可用 Object.assign()

嚴格定義物件的interface型別,確保資料完全在掌握範圍內,可用 Object.assign()。

此方案解決的痛點:

const info = reactive() ,當info需要重新初始化時,需要用Object.assign(),但是Object.assign() 本質是合併物件並返回結果的新物件。用作初始化資料會導致潛在的問題,尤其是資料非前端可控的情況下(例如介面獲得的資料)
所以用ref宣告,.value 賦值重新覆蓋,才是最穩妥的初始化!(而且這種方法不用擔心各種額外因素,降低心智負擔~~)
如果用ref.value儲存響應式物件,操作起來每次要.value也會很麻煩。 解決這個問題的程式碼就是對應的 let info = xx 和 初始化的 info = xx 這兩行程式碼!
陣列型別的情況下:reactive([1,2]),重新賦值導致丟失響應,ref.value操作也不太方便,因此也可採用這方法。(或者說引用型別目前都可採用這方法)
————————————————

<template lang="">
  <div>
    {{infoRef.newKey}}
    {{infoRef.bar}}
  </div>
</template>
<script lang='ts' setup>
import { ref,reactive } from 'vue';
 
const infoRef = ref<any>(source()) // template 裡必須繫結的是 infoRef 不能是 info !!
let info = infoRef.value // Js裡操作只操作 info 就可以不用 infoRef.value 了
function reset(){
  // 這樣需要重置整個響應式物件就不需要 Object.assign和考慮深拷貝問題了
  infoRef.value = source()
  // 重新初始化整個響應式物件時,用來資料操作的實際變數也需要重新賦值!
  info = infoRef.value
}
function source(){
  return {
    foo:1,
    bar:2,
    obj:{a:1}
  }
}
 
// 測試
setTimeout(() => {
  info.bar *= 110
  info.newKey = 666
}, 3000);
setTimeout(() => {
  reset()
}, 6000);
setTimeout(() => {
  info.bar = 987654321
}, 8000);
</script>

參考連結:https://blog.csdn.net/qq_38974163/article/details/122426426

                  https://blog.csdn.net/lijiahui_/article/details/122999787