=computed() =ref()

embedded/2024/11/25 8:11:11/

=computed() =ref()

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


1. ref()

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

2. computed()

作用
  • 用于定义基于其他响应式数据的 派生状态
  • computed 的值会根据依赖的响应式数据自动更新。
  • 适合用来处理需要动态计算的值。
用法
javascript">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 方法。
可写计算属性
javascript">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() 的示例:

javascript"><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 选项实现:

等价代码
javascript"><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

javascript">
<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>
javascript">
<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() 转换:

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

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

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

    javascript">// 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()
javascript">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()
javascript">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()
javascript"><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()
javascript"><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()
javascript"><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()
javascript"><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.ppmy.cn/embedded/140335.html

相关文章

RocketMQ 消息示例-延迟消息

生产者在确定一定时间间隔之后&#xff0c;这个消息才会被发送。其实也就是不会马上将消息发送出去&#xff0c;希望过一段时间以后再发送出去。 生产者在发送message的时候设置了一个延迟时间的等级&#xff0c;这里的3描述的是时间延迟的等级。这个消息会被延迟10s的时间 mes…

LeetCode-632. Smallest Range Covering Elements from K Lists [C++][Java]

目录 题目描述 解题思路 【C】 【Java】 LeetCode-632. Smallest Range Covering Elements from K Listshttps://leetcode.com/problems/smallest-range-covering-elements-from-k-lists/description/ 题目描述 You have k lists of sorted integers in non-decreasing o…

Vscode进行Java开发环境搭建

Vscode进行Java开发环境搭建 搭建Java开发环境(Windows)1.Jdk安装2.VsCode安装3.Java插件4.安装 Spring 插件5.安装 Mybatis 插件5.安装Maven环境6.Jrebel插件7.IntelliJ IDEA Keybindings8. 收尾 VS Code&#xff08;Visual Studio Code&#xff09;是由微软开发的一款免费、开…

STM32完全学习——使用标准库完成PWM输出

一、TIM2初始化 我这里使用的是STM32F407ZGT6这个芯片&#xff0c;我这里使用的是定时器TIM2来完成PWM输出&#xff0c;由于这里没有使用中断&#xff0c;因此不需要初始化NVIC&#xff0c;下面先来进行定时器的相关初始化 TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;R…

C#的数据类型总结:decimal ,double,float的区别

在 C# 中&#xff0c;decimal、double 和 float 都是用于表示数值类型的关键字&#xff0c;但它们在精度、范围和用途上有所不同。以下是它们的主要区别和适用场景的总结。 目录 1. decimal 2. double 3. float 主要比较 适用场景总结 注意点 1. decimal 类型大小: 16 字…

解释 Python 中的可变与不可变数据类型?

在 Python 中&#xff0c;数据类型分为可变&#xff08;mutable&#xff09;和不可变&#xff08;immutable&#xff09;两种。 理解这两种类型的区别对于编写高效、可靠的代码至关重要。 作为面试官&#xff0c;我会详细解释这两者的区别&#xff0c;并提供一些实际开发中的…

一文读懂 ESLint配置

你好,我是Qiuner. 为帮助别人少走弯路和记录自己编程学习过程而写博客 这是我的 github https://github.com/Qiuner ⭐️ ​ gitee https://gitee.com/Qiuner &#x1f339; 如果本篇文章帮到了你 不妨点个赞吧~ 我会很高兴的 &#x1f604; (^ ~ ^) 想看更多 那就点个关注吧 我…

正则表达式灾难:重新认识“KISS原则”的意义

大家好&#xff0c;这里是hikktn&#xff01; 最近&#xff0c;我在重读经典名著《The Art of Unix Programming》&#xff0c;又一次被那句广为人知的“KISS”原则&#xff08;Keep It Simple, Stupid&#xff09;吸引。这句计算机领域的金科玉律&#xff0c;很多人只停留在字…