1.reactive
reactive
能够将一个对象经过proxy代理后成为响应式对象返回
1.1语法
function reactive<T extends object>(target: T): UnwrapNestedRefs<T>
reactive<object>(target: object): object
- reactive不能包裹基本数据类型,若要包裹,需要外面套一层
{}
,将其转化为对象- reactive包裹引用类型,修改原引用数据的值,会影响到proxy代理的响应式对象,但是不会触发视图更新,同样修改proxy代理的响应式对象也会影响到源对象。
- reactive包裹ref对象,修改ref对象的值,会触发视图更新
- reactive对象,模板无法自动去掉外层的
{}
,可以同...toRefs
进行解构,就可以去掉外层的{}
。- reactive返回的数据不能直接赋值为一个新的对象或者数组,会丢失响应性
//TS下reactive声明的三种方式
import { defineComponent, reactive } from 'vue'
interface Student {
name: string
class?: string
age: number
}
export default defineComponent({
name: 'HelloWorld',
setup() {
const student = reactive<Student>({ name: '阿勇', age: 16 })
const student: Student = reactive({ name: '阿勇', age: 16 })
const student = reactive({ name: '阿勇', age: 16, class: 'cs' }) as Student
}
})
1.2 reactive包裹数据的三种方式
- 包裹基本数据类型(出错)
基本类型(数字、字符串、布尔值)在 reactive 中无法被创建成 proxy 对象,也就无法实现监听。无法实现响应式,特别是在ts中直接就报错了,具体可见。
<template>
<div>reactive:{{data}}</div>
<div><button @click="add"> 修改reactive</button></div>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
name: 'App',
setup(){
let value = 0
let data = reactive<{value:number}>({value})
const add = ():void=>{
data.value+= 1
}
return {
data,
add
}
}
})
</script>
- 包裹对象数据类型
模板绑定的时候,由于reactive返回的是proxy对象,因此在模板绑定的时候需要用[对象.属性]
的方式进行绑定和修改proxy对象的属性值。
<template>
<div>reactiveObj:{{reactiveObj}}</div>
<div><button @click="addObj"> 修改obj</button></div>
<div><button @click="addRef"> 修改reactive</button></div>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
name: 'App',
setup(){
let obj = {value:0}
let reactiveObj = reactive<{value: number}>(obj)
console.log(obj);
console.log(reactiveObj);
const addObj = ():void=>{
obj.value+= 1
console.log(obj);
console.log(reactiveObj);
}
const addRef = ():void=>{
reactiveObj.value+= 1
console.log(obj);
console.log(reactiveObj)
}
return {
reactiveObj,
addObj,
addRef
}
}
})
</script>
值得注意的是reactive包裹的数据不能直接赋值为一个新的对象,这种经常会在ajax请求数据返回的时候发生这种错误。
<template>
<button @click="change">赋值新对象</button>
<div>{{ proxyObj.name }}</div>
</template>
<script setup lang="ts">
import { reactive } from "@vue/reactivity";
let proxyObj = reactive({
name: "111"
})
const change = () => {
proxyObj = { name: "222" }
console.log(proxyObj);
}
</script>
赋值新对象丢失响应性
正确的做法是可以对reactive的属性挨个赋值,或者在外面再套一层,然后对内部的数据进行替换赋值、或者利用Object.assign()
//挨个赋值
<template>
<button @click="change">赋值新对象</button>
<div>{{ proxyObjnew.name }}</div>
</template>
<script setup lang="ts">
import { reactive, toRefs } from "@vue/reactivity";
let proxyObj = reactive({
name: "111"
})
const { data: proxyObjnew } = toRefs(proxyObj)
const change = () => {
proxyObj.name="222"
console.log(proxyObj);
}
</script>
//或者在外面再套一层,然后对内部的数据进行替换赋值
<template>
<button @click="change">赋值新对象</button>
<div>{{ proxyObjnew.name }}</div>
</template>
<script setup lang="ts">
import { reactive, toRefs } from "@vue/reactivity";
let proxyObj = reactive({
data: {
name: "111"
}
})
const { data: proxyObjnew } = toRefs(proxyObj)
const change = () => {
// proxyObj = { name: "222" }
proxyObj.data = { name: "222" }
console.log(proxyObj);
}
</script>
//利用Object.assign()
<template>
<button @click="change">赋值新对象</button>
<div>{{ proxyObj.name }}</div>
</template>
<script setup lang="ts">
import { reactive, toRefs } from "@vue/reactivity";
let proxyObj = reactive({
name: "111"
})
const change = () => {
proxyObj = Object.assign(proxyObj, { name: "222" })
console.log(proxyObj);
}
</script>
<style>
</style>
- 包裹ref数据
<template>
<div>reactiveObj:{{reactiveObj}}</div>
<div>ref:{{refData}}</div>
<div><button @click="addObj"> 修改reactive</button></div>
<div><button @click="addRef"> 修改原ref</button></div>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
name: 'App',
setup(){
let refData = ref<number>(0)
console.log(refData);
//返回
// {
// value:0
// }
let reactiveObj = reactive<{value: number}>(refData)
//返回proxy类型
// {
// value:0
// }
//注意不能let reactiveObj = reactive<{value: number}>({refData})
//你见过这种对象吗?
// {
// {
// value:0
// }
// }
console.log(reactiveObj);
console.log(refData);
const addObj = ():void=>{
reactiveObj.value+= 1
}
const addRef = ():void=>{
refData.value+= 1
}
return {
reactiveObj,
refData,
addObj,
addRef
}
}
})
</script>
2.ref
接受一个任意类型的并返回一个响应式且可变的 ref 对象
2.1语法
function ref<T>(value: T): Ref<T>
(alias) ref<any>(): Ref<any> (+2 overloads)
- ref仅仅是将原数据转化为响应式的Ref对象,其在原数据的外层包裹了一层对象
{value:原数据}
- ref数据在模板渲染过程中会自动提取外层包裹的对象,即提取外层的
.value
,但是在js代码中修改仍要通过.value
才能去修改- 对于引用类型的数据而言,由于Ref数据与原数据的引用地址是同一个地址因此ref包裹reactive数据或者引用类型的数据后,再去修改原来的reactive数据或者引用类型的数据,也会影响包裹后的ref数据。
- 修改引用类型数据,不会触发视图更新
- 修改reactive数据,会触发视图更新
2.2 ref包裹数据的三种方式
- 包裹基本数据类型
ref包裹基本数据,其只是将基本数据外面再包装了一层对象,所以实质上是
//Ref<{value:基本数据}>
Refdata = {
value:基本数据
}
<template>
<div>ref:{{data}}</div>
<div>reactive:{{data1}}</div>
<button @click="add"> add</button>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
name: 'App',
setup(){
let data = ref<number>(0)
let data1 = reactive({value:0})
console.log(data);
console.log(data1);
const add = ():void=>{
data.value+= 1
data1.value += 1
}
return {
data,
data1,
add
}
}
})
</script>
经过ref包裹的数据类型,在模板渲染中会自动提取其value,但是由于ref返回的是Ref对象,因此在js中我们修改ref后的值,需要用.value
的方式去修改
- 包裹引用数据类型
ref包裹引用数据,其只是将引用数据外面再包装了一层对象,所以实质上是
//Ref<{value:引用数据}>
Refdata = {
value:引用数据
}
<template>
<div>obj:{{obj}}</div>
<div>ref:{{data}}</div>
<div><button @click="addObj"> 修改obj</button></div>
<div><button @click="addRef"> 修改ref</button></div>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
name: 'App',
setup(){
let obj = {value:0}
let data = ref<{value: number}>(obj)
console.log(obj);
console.log(data);
const addObj = ():void=>{
obj.value+= 1
}
const addRef = ():void=>{
data.value.value+= 1
}
return {
obj,
data,
addObj,
addRef
}
}
})
</script>
ref包裹后,再去修改原对象,无法触发视图更新,但是能够影响到ref对象的值
- 包裹reactive数据
ref包裹reactive数据,其只是将reactive数据外面再包装了一层对象,所以实质上是
//Ref<{value:reactive数据}>
Refdata = {
value:reactive数据
}
在js代码中,我们修改就需要通过Refdata.value.reactive数据键名
去修改对应的键值
但是由于ref在模板绑定的时候,模板会自动提取ref对象的value,所以模板渲染实际上是
{
value:reactive数据
}
但是由于ref仅仅是将数据类型转化为响应式的ref对象,其并不是返回的proxy数据,所以它的引用地址仍然是reactive数据的引用地址,那么修改ref数据会影响到reactive数据,同时修改reactive数据也会影响到ref数据。
如下例:
<template>
<div>ref:{{data}}</div>
<div>reactive:{{data1}}</div>
<button @click="add"> add</button>
</template>
<script lang="ts">
import { reactive, ref, toRefs } from '@vue/reactivity'
import { defineComponent } from '@vue/runtime-core'
export default defineComponent({
name: 'App',
setup(){
let data1 = reactive<{value: number}>({value:0})
let data = ref<{value: number}>(data1)
console.log(data1);
console.log(data);
const add = ():void=>{
data.value.value+= 1
// data1.value += 1
}
return {
data,
data1,
add
}
}
})
</script>
·
修改原reactive对象会影响到ref对象,同时会出发视图更新
网友评论