当前位置: 首页 > news >正文

=computed() =ref()

=computed() =ref()

在 Vue 中,computed()ref() 是 Vue 3 组合式 API 的核心工具,它们分别用于 计算属性响应式数据。以下是它们的区别和用法:


1. ref()

作用
  • 用于创建响应式的单一数据。
  • 可以是基本类型(如字符串、数字、布尔值)或对象类型。
  • ref 的值发生变化时,依赖它的组件会自动重新渲染。
用法
import { ref } from 'vue';const count = ref(0); // 创建一个响应式变量// 修改值
count.value++; // 必须通过 .value 修改或访问 ref 的值console.log(count.value); // 输出: 1
特点
  • 基本类型ref 会将值包装为一个响应式对象,访问或修改时需要通过 .value
  • 对象类型:如果 ref 包裹的是对象,Vue 会自动将对象的属性变为响应式。
示例
import { ref } from 'vue';const user = ref({ name: 'Alice', age: 25 }); // 包裹一个对象// 修改对象属性
user.value.name = 'Bob';
console.log(user.value.name); // 输出: Bob

2. computed()

作用
  • 用于定义基于其他响应式数据的 派生状态
  • computed 的值会根据依赖的响应式数据自动更新。
  • 适合用来处理需要动态计算的值。
用法
import { ref, computed } from 'vue';const count = ref(0);// 定义一个计算属性
const doubleCount = computed(() => count.value * 2);console.log(doubleCount.value); // 输出: 0count.value++; // 修改 count 的值
console.log(doubleCount.value); // 输出: 2
特点
  • computed 的值是只读的,不能直接修改。
  • 如果需要可写的计算属性,可以传入 getset 方法。
可写计算属性
import { ref, computed } from 'vue';const count = ref(0);// 可写计算属性
const doubleCount = computed({get: () => count.value * 2,set: (newValue) => {count.value = newValue / 2; // 反向修改 count}
});doubleCount.value = 10; // 修改 doubleCount
console.log(count.value); // 输出: 5

3. ref()computed() 的区别

特性ref()computed()
用途定义响应式的单一数据定义基于其他响应式数据的派生状态
是否需要 .value
是否可写默认不可写(可通过 getset 实现)
依赖性独立存在,不依赖其他响应式数据依赖其他响应式数据
性能直接存储值,简单高效有缓存机制,只有依赖数据变化时才重新计算

4. 综合示例

以下是一个同时使用 ref()computed() 的示例:

<script setup>
import { ref, computed } from 'vue';// 定义响应式数据
const price = ref(100);
const quantity = ref(2);// 定义计算属性
const total = computed(() => price.value * quantity.value);// 修改响应式数据
price.value = 150;console.log(total.value); // 输出: 300
</script><template><div><p>单价: {{ price }}</p><p>数量: {{ quantity }}</p><p>总价: {{ total }}</p></div>
</template>

5. 在 Options API 中的等价用法

在 Vue 3 的 Options API 中,ref()computed() 的功能可以通过 datacomputed 选项实现:

等价代码
<script>
export default {data() {return {price: 100, // 等价于 ref(100)quantity: 2 // 等价于 ref(2)};},computed: {total() {return this.price * this.quantity; // 等价于 computed(() => price.value * quantity.value)}}
};
</script><template><div><p>单价: {{ price }}</p><p>数量: {{ quantity }}</p><p>总价: {{ total }}</p></div>
</template>

6. 总结

  • ref():用于定义响应式的单一数据,适合存储基本类型或对象。
  • computed():用于定义基于其他响应式数据的派生状态,具有缓存机制。
  • 组合使用ref() 定义基础数据,computed() 定义基于基础数据的动态值。

case 2


<script setup>  
import { ref, computed } from 'vue';  // 原始数据  
const data = ref([  { position: { x: 1, y: 2 } },  { position: { x: 3, y: 4 } },  { position: { x: 5, y: 6 } }  
]);  // 数据转换函数  
const convertData = (sourceData) => {  try {  const paths = sourceData  .filter(item => item?.position && typeof item.position === 'object')  .map(item => item.position);  return [{  paths: paths  }];  } catch (error) {  console.error('数据转换错误:', error);  return [{ paths: [] }];  }  
};  // 计算属性  
const convertTodata = computed(() => convertData(data.value));  // 更新数据的方法  
const updateData = (newData) => {  data.value = newData;  
};  
</script>  <template>  <div class="p-4">  <h2 class="text-xl mb-4">转换后的数据:</h2>  <pre class="bg-gray-100 p-4 rounded">  {{ JSON.stringify(convertTodata, null, 2) }}  // 使用 JSON.stringify 将 convertTodata 的结果格式化为 JSON 字符串并显示在页面</pre>  </div>  
</template>

<script>  
export default {  name: 'DataConverter',  // ref() -> data()  data() {  return {  // const data = ref([...]) 变成:  data: [  { position: { x: 1, y: 2 } },  { position: { x: 3, y: 4 } },  { position: { x: 5, y: 6 } }  ]  }  },  // computed() -> computed: {}  computed: {  // const convertTodata = computed(() => ...) 变成:  convertTodata() {  return this.convertData(this.data);  }  },  methods: {  convertData(sourceData) {  try {  const paths = sourceData  .filter(item => item?.position && typeof item.position === 'object')  .map(item => item.position);  return [{  paths: paths  }];  } catch (error) {  console.error('数据转换错误:', error);  return [{ paths: [] }];  }  },  // const updateData = (newData) => { data.value = newData } 变成:  updateData(newData) {  this.data = newData;  }  }  
};  
</script>  <template>  <div class="p-4">  <h2 class="text-xl mb-4">转换后的数据:</h2>  <pre class="bg-gray-100 p-4 rounded">  {{ JSON.stringify(convertTodata, null, 2) }}  </pre>  </div>  
</template>  <style scoped>  
.p-4 {  padding: 1rem;  
}  .text-xl {  font-size: 1.25rem;  line-height: 1.75rem;  
}  .mb-4 {  margin-bottom: 1rem;  
}  .bg-gray-100 {  background-color: #f3f4f6;  
}  .rounded {  border-radius: 0.25rem;  
}  
</style>

主要转换规则

  1. ref() 转换:

    // Composition API  
    const data = ref([...])  // Options API  
    data() {  return {  data: [...]  }  
    }  
    
  2. computed() 转换:

    // Composition API  
    const result = computed(() => {...})  // Options API  
    computed: {  result() {  return {...}  }  
    }  
    
  3. 方法转换:

    // Composition API  
    const updateData = (newData) => {  data.value = newData  
    }  // Options API  
    methods: {  updateData(newData) {  this.data = newData  }  
    }  
    
  4. 数据访问:

    // Composition API  
    data.value  // Options API  
    this.data  
    

=computed() 能改为 =ref() 吗

在 Vue 3 中,computed()ref() 是不同的工具,虽然它们都可以创建响应式数据,但它们的用途和行为不同。computed() 不建议直接改为 ref(),因为它们的核心区别在于:

  • ref() 是用于存储和管理响应式的单一数据。
  • computed() 是用于基于其他响应式数据派生出新的值,并且具有 缓存机制

如果你想用 ref() 替代 computed(),需要手动实现类似 computed() 的功能,但这通常不推荐,因为 computed() 已经为你处理了依赖追踪和缓存。=ref() 会丢失 computed() 的依赖追踪和缓存特性。


什么时候可以用 ref() 替代 computed()

如果你的计算逻辑非常简单,且不需要依赖缓存机制,可以用 ref()watchEffect()watch() 来实现类似的功能。


如何用 ref() 替代 computed()

以下是一个示例,展示如何用 ref()watchEffect() 替代 computed()

原始代码:使用 computed()
import { ref, computed } from 'vue';const count = ref(0);
const doubleCount = computed(() => count.value * 2);console.log(doubleCount.value); // 输出: 0count.value++;
console.log(doubleCount.value); // 输出: 2
改为使用 ref()watchEffect()
import { ref, watchEffect } from 'vue';const count = ref(0);
const doubleCount = ref(0);// 使用 watchEffect 手动更新 doubleCount
watchEffect(() => {doubleCount.value = count.value * 2;
});console.log(doubleCount.value); // 输出: 0count.value++;
console.log(doubleCount.value); // 输出: 2

对比分析

特性computed()ref() + watchEffect()watch
依赖追踪自动追踪依赖否, 使用 watchEffect 手动更新值否, 使用 watch 手动更新值
缓存机制有缓存,每次使用时使用的预先计算存储的的 cache,依赖变化时重新计算, 使用时使用的重新计算存储的的 new cache没有缓存,每次使用时重新计算,依赖变化时重新计算否, 每次 data(){} 变化都会重新执行
代码复杂度简洁,直接定义计算逻辑需要手动更新值,代码稍显冗长
适用场景适合派生状态,依赖多个响应式数据适合简单逻辑或不需要缓存的场景

完整示例:从 computed() 改为 ref()

假设你有一个组件,使用 computed() 来计算数据:

原始代码:使用 computed()
<script setup>
import { ref, computed } from 'vue';const price = ref(100);
const quantity = ref(2);// 计算总价
const total = computed(() => price.value * quantity.value);
</script><template><div><p>单价: {{ price }}</p><p>数量: {{ quantity }}</p><p>总价: {{ total }}</p></div>
</template>
改为使用 ref()watchEffect()
<script setup>
import { ref, watchEffect } from 'vue';const price = ref(100);
const quantity = ref(2);// 使用 ref 存储总价
const total = ref(0);// 手动更新 total 的值
watchEffect(() => {total.value = price.value * quantity.value;
});
</script><template><div><p>单价: {{ price }}</p><p>数量: {{ quantity }}</p><p>总价: {{ total }}</p></div>
</template>

原始代码:使用 computed()
<script>  
export default {  name: 'DataConverter',  // ref() -> data()  data() {  return {  // const data = ref([...]) 变成:  data: [  { position: { x: 1, y: 2 } },  { position: { x: 3, y: 4 } },  { position: { x: 5, y: 6 } }  ]  }  },  // computed() -> computed: {}  computed: {  // const convertTodata = computed(() => ...) 变成:  convertTodata() {  return this.convertData(this.data);  }  },  methods: {  convertData(sourceData) {  try {  const paths = sourceData  .filter(item => item?.position && typeof item.position === 'object')  .map(item => item.position);  return [{  paths: paths  }];  } catch (error) {  console.error('数据转换错误:', error);  return [{ paths: [] }];  }  },  // const updateData = (newData) => { data.value = newData } 变成:  updateData(newData) {  this.data = newData;  }  }  
};  
</script>  <template>  <div class="p-4">  <h2 class="text-xl mb-4">转换后的数据:</h2>  <pre class="bg-gray-100 p-4 rounded">  {{ JSON.stringify(convertTodata, null, 2) }}  </pre>  </div>  
</template>  
改为使用 ref()watchEffect()
<template>  <div class="p-4">  <h2 class="text-xl mb-4">转换后的数据:</h2>  <pre class="bg-gray-100 p-4 rounded">  {{ JSON.stringify(convertTodata, null, 2) }}  </pre>  </div>  
</template>  <script>  
export default {  data() {  return {  // 原始数据  data1: [  { position: { x: 1, y: 2 } },  { position: { x: 3, y: 4 } },  { position: { x: 5, y: 6 } }  ],irrelevantData: 'something', // 无关数据 // 将 computed 改为 data 中的属性  // 移除了 computed 属性:原来的计算属性被转换为 data 中的普通响应式数据// 无自动追踪依赖,需watch 无缓存机制 不是只有依赖变化时( data1.value 变化时)才重新计算,每次 data ( 指总的 data(){},例如 irrelevantData change ) 变化都会执行convertTodata: [{ paths: [] }],}  },  // 监听 data ( 指总的 data(){},例如 irrelevantData change )的变化,更新 convertTodata  watch: {  data: {  // 指总的 data(){}immediate: true, // 确保初始化时执行一次,立即执行一次  handler(newData) {  // 当 data 变化时更新 convertTodata  this.convertTodata = this.convertData(newData);  }  }  },  methods: {  convertData(sourceData) {  try {  const paths = sourceData  .filter(item => item?.position && typeof item.position === 'object')  .map(item => item.position);  return [{  paths: paths  }];  } catch (error) {  console.error('数据转换错误:', error);  return [{ paths: [] }];  }  },  updateData(newData) {  this.data = newData;  }  }  
}  
</script>

注意事项

  1. 性能问题

    • computed() 有缓存机制,只有依赖的数据发生变化时才会重新计算。
    • ref() + watchEffect() 每次依赖变化都会重新执行逻辑,可能会带来性能开销。
  2. 代码简洁性

    • computed() 更加简洁,适合大多数场景。
    • ref() + watchEffect() 需要手动更新值,代码稍显冗长。
  3. 推荐使用场景

    • 如果你的逻辑依赖多个响应式数据,并且需要缓存,优先使用 computed()
    • 如果你的逻辑非常简单,或者不需要缓存,可以使用 ref() + watchEffect()

总结

  • computed() 是首选:它更简洁、性能更好,适合大多数场景。
  • ref() 替代 computed():可以通过 watchEffect() 手动实现,但代码复杂度会增加,且没有缓存机制。

参考:

=ref() =computed()

http://www.lryc.cn/news/491046.html

相关文章:

  • webgl threejs 云渲染(服务器渲染、后端渲染)解决方案
  • 【shell编程】函数、正则表达式、文本处理工具
  • 解决 npm xxx was blocked, reason: xx bad guy, steal env and delete files
  • 如何进行高级红队测试:OpenAI的实践与方法
  • Java:二维数组
  • Android 天气APP(三十七)新版AS编译、更新镜像源、仓库源、修复部分BUG
  • Xilinx IP核(3)XADC IP核
  • 计算机网络socket编程(2)_UDP网络编程实现网络字典
  • c#窗体列表框(combobox)应用——省市区列表选择实例
  • Nginx 架构与设计
  • python Flask指定IP和端口
  • 多线程 相关面试集锦
  • 【数据结构】—— 线索二叉树
  • uni-app 发布媒介功能(自由选择媒介类型的内容) 设计
  • How to update the content of one column in Mysql
  • URL在线编码解码- 加菲工具
  • Python3 爬虫 Scrapy的安装
  • QT中QString类的各种使用
  • linux 网络安全不完全笔记
  • uniapp将图片url转换成base64支持app和h5
  • odoo17 档案管理之翻译2
  • 风尚云网前端学习:制作一款简易的在线计算器
  • Android蓝牙架构,源文件目录/编译方式学习
  • ubuntu中使用ffmpeg和nginx推流rtmp视频
  • strongswan测试流程
  • [CKS] CIS基准测试,修复kubelet和etcd不安全项
  • Linux/Windows/OSX 上面应用程序重新启动运行。
  • React拆分组件中的传值问题
  • RocketMQ的使⽤
  • Android Studio 设置不显示 build-tool 无法下载