Vue 3 引入了全新的响应式系统,主要通过 ref
和 reactive
这两个 API 来实现。下面我将通过具体代码示例详细讲解它们的用法和区别。
1. ref - 基础响应式 API
ref
用于创建响应式的基本类型数据(如字符串、数字、布尔值),也可以用于对象和数组。
基本用法
import { ref } from 'vue'// 创建一个响应式的数字
const count = ref(0)// 创建一个响应式的字符串
const message = ref('Hello Vue 3!')// 创建一个响应式的布尔值
const isVisible = ref(false)
模板中使用
<template><div><p>{{ count }}</p><button @click="increment">增加</button></div>
</template><script setup>
import { ref } from 'vue'const count = ref(0)function increment() {count.value++ // 注意需要通过 .value 访问
}
</script>
为什么需要 .value
ref
返回的是一个响应式对象,这个对象有一个 .value
属性指向内部值:
-
在 JavaScript 中需要通过
.value
访问 -
在模板中自动解包,不需要
.value
2. reactive - 对象响应式 API
reactive
用于创建响应式的对象或数组。
基本用法
import { reactive } from 'vue'// 创建一个响应式对象
const user = reactive({name: '张三',age: 25,address: {city: '北京'}
})// 创建一个响应式数组
const list = reactive(['苹果', '香蕉', '橙子'])
模板中使用
<template><div><p>姓名: {{ user.name }}</p><p>年龄: {{ user.age }}</p><button @click="growUp">长大一岁</button></div>
</template><script setup>
import { reactive } from 'vue'const user = reactive({name: '张三',age: 25
})function growUp() {user.age++ // 直接修改属性,不需要 .value
}
</script>
3. 实际案例对比
案例1:计数器(ref vs reactive)
<template><!-- ref 实现 --><div><p>ref 计数: {{ count }}</p><button @click="count++">增加</button></div><!-- reactive 实现 --><div><p>reactive 计数: {{ state.count }}</p><button @click="state.count++">增加</button></div>
</template><script setup>
import { ref, reactive } from 'vue'// ref 方式
const count = ref(0)// reactive 方式
const state = reactive({count: 0
})
</script>
案例2:表单处理(reactive 更适用)
<template><form @submit.prevent="submitForm"><input v-model="form.username" placeholder="用户名"><input v-model="form.password" type="password" placeholder="密码"><button type="submit">提交</button></form>
</template><script setup>
import { reactive } from 'vue'const form = reactive({username: '',password: ''
})function submitForm() {console.log('提交数据:', form)
}
</script>
4. 何时使用 ref vs reactive
特性 | ref | reactive |
---|---|---|
适用类型 | 基本类型、对象、数组 | 对象、数组 |
模板访问 | 自动解包,无需 .value | 直接访问属性 |
JS 中访问 | 需要 .value | 直接访问属性 |
重新赋值 | 可以整个替换 | 不能直接替换整个对象 |
TypeScript 支持 | 需要 Ref 类型 | 直接使用接口类型 |
最佳实践建议
-
基本类型:使用
ref
const count = ref(0)
2. 对象/复杂数据结构:使用 reactive
const form = reactive({username: '',password: ''
})
3.组合使用:在对象中需要基本类型时
const state = reactive({count: ref(0), // 对象属性可以是 refname: 'Vue'
})
// 使用时 state.count 会自动解包
5. 实战案例:审批组件中的响应式使用
回到原始审批组件,我们可以看到实际应用:
// 使用 reactive 管理表单数据
const form = reactive({});// 使用 ref 管理组件状态
const visible = ref(false)
const loading = ref(false)
const formId = ref("")
const processName = ref('')// 使用 ref 引用子组件
const agreeHandler = ref();
const refuseHandler = ref();
const hospPlanRef = ref();
这种组合使用方式既保持了代码的简洁性,又充分利用了 Vue 3 响应式系统的能力。