ref 和 reactive 区别

前言

ref 和 reactive是Vue 3中响应式编程的核心。在Vue中,响应式编程是一种使数据与UI保持同步的方式。当数据变化时,UI会自动更新,反之亦然。这种机制大大简化了前端开发,使我们能够专注于数据和用户界面的交互,而不必手动处理DOM更新。

ref

ref是Vue 3中的一个简单响应式API,用于创建一个包装基本数据类型的响应式引用(也可以包装复杂类型,只不过底层还是由reactive的方式实现的)。它的主要优点是能够轻松包装基本数据类型,并且具有清晰的访问和更新方式

ref创建基本类型的响应式数据

html 复制代码
<script lang="ts" setup name="Car">
    import { ref } from 'vue'

    let brand = ref("奔驰")
    let price = ref(30)

    function changePrice() {
      price.value += 10
    }  

    function changeBrand() {
      brand.value = "宝马"
    }
</script>

<template>
  <div class="class">
    <h2>品牌:{{ brand }}</h2>
    <h2>价格:{{ price }}万</h2>
    <button @click="changePrice">点击价格+10</button>
    <br/>
    <button @click="changeBrand">修改品牌</button>
  </div>
</template>

<style scoped>
  .class {
      color: rgb(214, 12, 12);
      font-size: 20px;
      height: 20%;
  }

  button {
      background-color: blue;
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 5px;
      cursor: pointer;
      margin-top: 10px;
  }
</style>

在修改使用ref定义的响应式数据时要用***.value的形式去修改。

ref创建对象类型的响应式数据

html 复制代码
<script lang="ts" setup name="Car">
    import { ref } from 'vue'

    let wall = ref({color: '白色', height: 5, width: 6})
    
    function changeWallColor(color: string) {
        wall.value.color = color
    }
    function changeWallHeight(height: number) {
        wall.value.height = height
    }
    function changeWallWidth(width: number) {
        wall.value.width = width
    }
</script>

<template>
  <div class="wall">
    <h2>颜色:{{ wall.color }}</h2>
    <h2>高:{{ wall.height }}</h2>
    <h2>宽:{{ wall.width }}</h2>
    <button @click="changeWallColor('红色')">修改颜色 </button>
    <hr>
    <button @click="changeWallHeight(10)">修改高度 </button>
    <hr>
    <button @click="changeWallWidth(12)">修改宽度 </button>
  </div>

</template>

<style scoped>
  .wall {
    width: 500px;
    background-color: #e6f7ff; /* 浅蓝色背景 */
    border: 1px solid #b3e0ff;
    border-radius: 10px;
    padding: 20px;
    margin: 20px 0 ;
    color: #333;
    font-size: 18px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  }

  h2 {
      margin: 10px 0;
  }

  button {
      background-color: #007bff;
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 5px;
      cursor: pointer;
      margin-top: 10px;
      transition: background-color 0.3s ease;
  }

  button:hover {
      background-color: #0056b3;
  }

  hr {
      border: 0;
      border-top: 1px solid #ddd;
      margin: 20px 0;
  }

  ul {
      list-style-type: none;
      padding: 0;
  }

  li {
      background-color: #fff;
      border: 1px solid #ddd;
      border-radius: 5px;
      padding: 10px;
      margin: 10px 0;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }
</style>

ref创建对象类型的响应式数据在修改数据内容时,同样需要用.value去修改。

reactivate

reactivate 创建对象类型的响应式数据

html 复制代码
<script lang="ts" setup name="Car">
    import { reactive, ref } from 'vue'

    let person = reactive({name: '张三', age: 25, gender: '男'})
    let games = reactive([{name: '王者荣耀', level: 80}, {name: '绝地求生', level: 90}])

    function changeName() {
      person.name = '李四'
    }  

    function changeAge() {
      person.age += 1
    }

    function changeGender() {
      person.gender = '女'
    }

    function addGame() {
      games.push({name: '英雄联盟', level: 85})
    }

    function changeGame() {
      games[0].level += 10
    }
</script>

<template>
  <div class="person">
    <h2>姓名:{{ person.name }}</h2>
    <h2>年龄:{{ person.age }}</h2>
    <h2>性别:{{ person.gender }}</h2>
    <button @click="changeName">修改姓名</button>
    <hr>
    <button @click="changeAge">修改年龄</button>
    <hr>
    <button @click="changeAge">修改性别</button>
  </div>

  <div class="games">
    <h2>游戏列表</h2>
    <ul>
      <li v-for="(game, index) in games" :key="index">{{ game.name }} - {{ game.level }}级</li>
    </ul>
    <button @click="addGame">添加游戏</button>
    <hr>
    <button @click="changeGame">修改游戏</button>
  </div>
</template>

<style scoped>
  .person {
    width: 500px;
    background-color: #e6f7ff; /* 浅蓝色背景 */
    border: 1px solid #b3e0ff;
    border-radius: 10px;
    padding: 20px;
    margin: 20px 0 ;
    color: #333;
    font-size: 18px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  }

  .games {
    width: 500px;
    background-color: #f2f2f2; /* 浅灰色背景 */
    border: 1px solid #ddd;
    border-radius: 10px;
    padding: 20px;
    margin: 20px 0;
    color: #333;
    font-size: 18px;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  }

  h2 {
      margin: 10px 0;
  }

  button {
      background-color: #007bff;
      color: white;
      border: none;
      padding: 10px 20px;
      border-radius: 5px;
      cursor: pointer;
      margin-top: 10px;
      transition: background-color 0.3s ease;
  }

  button:hover {
      background-color: #0056b3;
  }

  hr {
      border: 0;
      border-top: 1px solid #ddd;
      margin: 20px 0;
  }

  ul {
      list-style-type: none;
      padding: 0;
  }

  li {
      background-color: #fff;
      border: 1px solid #ddd;
      border-radius: 5px;
      padding: 10px;
      margin: 10px 0;
      box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  }
</style>

响应式实现

为什么推荐使用ref而不是reactive

reactive在使用过程中存在一些局限性,如果不额外注意这些问题,可能会给开发带来一些不便。与此不同,ref更像是Vue2时代的option API中的data的替代品,可以存放任何数据类型,而reactive声明的数据类型则仅限于对象。

总体来说,非必要的情况下最好避免使用reactive。官方文档也强烈推荐使用ref()作为声明响应式状态的主要API。以下是详细原因:

局限性问题: reactive本身存在一些局限性,可能会在开发过程中引发一些问题。这需要额外的注意力和处理,否则可能对开发造成麻烦。

数据类型限制: reactive声明的数据类型仅限于对象,而ref则更加灵活,可以容纳任何数据类型。这使得ref更适合一般的响应式状态的声明。

官方推荐: 官方文档强烈建议使用ref()作为声明响应式状态的首选。这是因为ref更简单、更直观,同时避免了reactive可能引发的一些问题。

总的来说:除非有特定的需求需要使用reactive,否则在大多数情况下更推荐使用ref()。

相关推荐
Dream-Y.ocean36 分钟前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn2 小时前
性能监控
前端
Highcharts.js2 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn2 小时前
构建工具
前端
FRing033 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷3 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen5 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒5 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫5 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus6 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude