一、是什么?
ref和reactive是Vue3中用来实现数据响应式的API,一般情况下,ref
定义基本数据类型,reactive
定义引用数据类型。
二、基础用法
1. ref
ref的参数一般是基本数据类型
,也可以是对象类型;如果参数是对象类型,其实底层的本质还是reactive,系统就会自动将ref转换为reactive;我们如果去访问ref定义的值,那么就使用.value
的属性去访问定义的数据;ref的底层原理同reactive一样,都是Proxy。
基础用法
let num = ref(0) // 定义
let isShow = ref(false) // 定义
const onChange = () => {
num.value++ // js使用
isShow.value = true // js使用
}
<!-- Vue3模板引用使用 -->
<Modal v-model="isShow"></Modal>
2. reactive
reactive定义引用数据类型(以对象和数组举例),它能够将复杂数据类型的内部属性或者数据项声明为响应式数据,所以reactive的响应式是深层次的,其底层是通过ES6的Proxy来实现数据响应式,相对于Vue2的Object.defineProperty,具有能监听增删操作,能监听对象属性的变化等优点。
基础用法
const pageConfig = reactive({
pageNum: 1,
pageSize: 10
}) // 定义
const onChange = () => {
pageConfig.pageNum = 2;
pageConfig.pageSize = 20;
}
<!-- Vue3模板引用使用 -->
<Page :current="pageConfig.pageNum"></Page>
若用reactive定义基本数据类型,Vue3会报警告错误,如图
const str = reactive('字符串')
3. ref和reactive定义数组对比
ref定义数组
const tableData = ref([]) // 定义
const getTableData = async () => {
const { data } = await getTableDataApi() // 模拟接口获取表格数据
tableData.value = data // 修改
}
<!-- Vue3模板引用使用 -->
<Table :data="tableData"></Table>
以我们常用的表格数据举例,可以看到,ref定义数组与定义基本数据类型没什么差别,接下来看看reactive
const tableData = reactive([]) // 定义
const getTableData = async () => {
const { data } = await getTableDataApi() // 模拟接口获取表格数据
tableData = data // 修改,错误示例,这样赋值会使tableData失去响应式
}
<!-- Vue3模板引用使用 -->
<Table :data="tableData"></Table>
需要注意的是,reactive定义的数组使用 tableData = data 的修改方式会造成 tableData 响应式丢失,解决方法如下:
// 方法一:改为 ref 定义
const tableData = ref([])
const getTableData = async () => {
const { data } = await getTableDataApi()
tableData.value = data // 使用.value重新赋值
}
// 方法二:使用 push 方法
const tableData = reactive([])
const getTableData = async () => {
const { data } = await getTableDataApi()
tableData.push(...data) // 先使用...将data解构,再使用push方法
}
// 方法三:定义时数组外层嵌套一个对象
const tableData = reactive({ list:[] })
const getTableData = async () => {
const { data } = await getTableDataApi()
tableData.list = data // 通过访问list属性重新赋值
}
4. Proxy vs defineProperty
reactive方法内部是利用ES6的Proxy API来实现的,这里与Vue2中的defineProperty方法有本质的区别。
- defineProperty只能单一地监听已有属性的修改或者变化,无法检测到对象属性的新增或删除,而Proxy可以轻松实现;
- defineProperty无法监听属性值是数组类型的变化,而Proxy可以轻松实现。
三、ref 和reactive的区别
- ref用于定义基本类型和引用类型,reactive仅用于定义引用类型;
- reactive只能用于定义引用数据类型的原因在于内部是通过ES6的Proxy实现响应式的,而Proxy不适用于基本数据类型;
- ref定义对象时,底层会通过reactive转换成具有深层次的响应式对象,所以ref本质上是reactive的再封装;
- 在JS中我们如果去对数据进行操作,在
ref
定义的数据中,使用变量.value
;访问reactive不需要; - 在定义数组时,建议使用ref,从而可避免reactive定义时值修改导致的响应式丢失问题。