創建不可變的響應式數據:readonly()

Vue 3 提供的 readonly() 函式可用來建立 不可變 的響應式數據,防止外部修改特定狀態。在某些情況下(如跨組件傳遞資料時),這能有效避免資料被意外改動。


🔹 基本用法

readonly() 會建立一個代理對象,使其內容變為只讀
⚠️ 注意:如果來源本身是響應式資料,變更仍會同步反映在 readonly 版本中。

<script setup>
import { ref, readonly } from 'vue';

const count = ref(10);
const readOnlyCount = readonly(count);

count.value = 20;        // ✅ 可以修改
readOnlyCount.value = 30; // ❌ 會報錯 (因為是只讀)
</script>

🔹 作用於 reactive() 物件

readonly() 作用於 reactive() 回傳的物件時,該物件的所有屬性皆會變成只讀。

<script setup>
import { reactive, readonly } from 'vue';

const user = reactive({
  name: 'Jack',
  age: 25
});

const readOnlyUser = readonly(user);

user.name = 'Tom';             // ✅ 原始對象仍可修改
readOnlyUser.name = 'Mike';    // ❌ 會報錯 (因為是 readonly)
</script>

🔹 搭配 toRefs() 的使用

readonly() 可以與 toRefs() 一起使用,將只讀物件轉換為獨立的響應式屬性,但這些屬性仍然是只讀的。

<script setup>
import { reactive, readonly, toRefs } from 'vue';

const user = reactive({ name: 'Jack', age: 25 });
const readOnlyUser = readonly(user);

const { name, age } = toRefs(readOnlyUser);

name.value = 'Tom'; // ❌ 會報錯 (因為是 readonly)
</script>

🔹 搭配 watch() 使用

readonly() 不影響資料的響應性,因此可以用於 watch() 中監聽其變化。

<script setup>
import { ref, readonly, watch } from 'vue';

const count = ref(0);
const readOnlyCount = readonly(count);

watch(readOnlyCount, (newVal) => {
  console.log('count 變更為:', newVal);
});

count.value++;           // ✅ 會觸發 watch
readOnlyCount.value++;   // ❌ 會報錯
</script>

🔹 搭配 provide / inject 使用

在組件間傳遞資料時,使用 readonly() 可以保護資料不被子元件意外修改,保持狀態一致性。

父元件

<script setup>
import { ref, provide, readonly } from 'vue';

const theme = ref('dark');

// 提供 readonly 版本的資料給子元件使用
provide('theme', readonly(theme));
</script>

<template>
  <ChildComponent />
</template>

子元件

<script setup>
import { inject } from 'vue';

const theme = inject('theme');

console.log(theme.value);   // ✅ 可讀取 "dark"
theme.value = 'light';      // ❌ 會報錯 (因為是 readonly)
</script>

📌 補充說明

  • readonly() 不會深層凍結物件(不是 deep freeze),但它會使所有屬性透過 Vue proxy變得不可改變。
  • 原始對象(如 refreactive)仍然可變,readonly 只是一個包裝。
  • 若要完全避免狀態被修改,請搭配應用層邏輯或在程式碼設計中不暴露原始對象。

📚 參考資料