ref取值或赋值时需要加.value
let form = ref({age:18})
// 修改值
form.value.age = 28
一般使用在简单的数据类型,如:string , number,Boolean,Symbol或单值对象【即:只有一个属性值的对象】(如:{ count: 1 })
import { ref , isRef , shallowRef , triggerRef , customRef } from 'vue'
type U = { name:string }
const user = ref({name:"Fish"}) // ref( )
import type { Ref } from 'vue'
type U = { name:string }
const user:Ref = ref({name:"Fish"}) // :Ref
const user = ref({name:"Fish"}) // 使用ref()进行包裹, 自动推断
修改值时,返回的是ES6的一个类,有个属性.value,修改或取值(CURD)必须加.value,修改后放在value中的Proxy中。
返回boolean
isRef( user ) // 返回 true
shallowRef是浅层次响应,在user.value.name中,只到.value赋值,不能到.name
const user = shallowRef({ name:"Fish" })
const change = () => {
user.value.name = 'Fisher'
console.log(user) // 值已改变
// shallowRef:{{ user }} // 视图不改变
}
const user = shallowRef({ name:"Fish" })
const change = () => {
user.value = {name:'Fisher'}
console.log(user) // 值已改变
// shallowRef:{{ user }} // 视图也改变
}
注意:ref , shallowRef不能同时使用。
否则,shallowRef会受到ref的影响,造成shallowRef视图的更新。
因为在ref底层更新逻辑时,会调用triggerRef函数。
const user = shallowRef({name:Fish})
const change = () => {
user.value.name = 'Fisher'
triggerRef(user)
console.log(user) // 视图将改变
}
function MyRef( value:T ){
return customRef((track,trigger)=>{
return {
get(){
track() // 收集依赖
return value
}
set( newValue ){
console.log('触发------')
value = newValue
trigger() // 触发依赖
}
}
})
}
// 1.script
const obj = MyRef('Fish')
// 2.视图中
{{ obj }}
// 3.改值也需要加.value [script]
obj.value = '修改啦'
// 简单防抖
function MyRef( value:T ){
let timer:any
return customRef((track,trigger)=>{
return {
get(){
track() // 收集依赖
return value
}
set( newValue ){
clearTimeout(timer)
timer = setTimeout(()=>{
console.log('触发------')
value = newValue
timer = null
trigger() // 触发依赖
},500)
}
}
})
}
test
{{ user }}
使用 ref:基础类型值(String,Number,Boolean,Symbol) 或单值对象【即:只有一个属性值的对象】(如:{ count: 1 })
使用 reactive:引用类型值(Object、Array、Map、Set、WeakMap、WeakSet)
ref 与 reactive 都是把变量变成响应式变量,使用ref或者reactive对其进行包裹
// 示例
let user.name = ref("Fish") // ref 支持所有类型
let form = reactive("Fish") // 不能使用string类型,所以出错
let form = reactive({name:'Fish',age:18}) // 正确表示
一般在复杂的数据类型使用。使用reactive取值或赋值(CURD)时无需.value
type U = { name:string,age:number }
let form = reactive({
name:"Fish",
age:18
})
// 修改值
form.age = 28
type U = { name:string,age:number }
const user = reactive({name:"Fish"}) // reactive( )
- {{ item }}
如果是调用接口,点击添加,不显示?
因为reactive是一个proxy代理的对象,直接赋值的话,就覆盖proxy对象了,从而会破坏reactive的proxy对象。
所以不能直接赋值,否则破坏响应对式对象了。
- {{ item }}
// 直接赋值
list = res
// 修改为
list.push(...res)
添加一个对象arr,把数组作为一个属性
// 原代码
// let list = reactive([])
// 代码修改为
let list = reactive<{ arr: string[] }>({ arr: [] })
// 同时调整
// {{ item }}
// 调整后内容
{{ item }}
// --------------------------------
// 原代码
// list.push(...res)
// 修改为
list.arr = res
// 或者修改为
list.arr.push(...res)
- {{ item }}
readonly 属性强制赋值不改变;如果原始对象变化,则改变
let obj = reactvie({name:'Fish'})
const read = readonly(obj)
read.name = 'Fisher' // 无法分配到 "name" ,因为它是只读属性。
obj.name = 'Fisher' // 则,obj、read 都将改变
参考shallowRef,原理相同
针对一个响应式对象(reactive 封装)的 prop(属性)创建一个ref,且保持响应式
两者 保持引用关系。
toRefs 是一种用于破坏响应式对象并将其所有属性转换为 ref 的实用方法
将响应式对象(reactive封装)转成普通对象
对象的每个属性(Prop)都是对应的ref
两者保持引用关系
ref |
toRef |
拷贝,修改响应式数据不会影响原始数据 |
引用,修改响应式数据会影响原始数据 |
ref数据发生改变,视图自动更新 |
只能修改响应对象的值 非响应式对象使用toRef视图无变化 |
创建一个响应式的数据对象,传入的为基本数据类型 |
接收两个参数 第一个参数是对象,第二个参数是对象的属性 |
toRef |
如果是ref 对象,直接返回;否则,创建一个类ref 对象。 类ref 对象只是做了值的改变,并未处理收集依赖和触发依赖的过程。所以,普通对象无法更新视图。 如果原始对象是响应式的,则会更新视图并改变数据
|
toRefs |
批量创建ref对象(普通对象),方便解构 当想解构reactive对象时,记得使用toRefs,如果直接解构是没办法使用响应式的 toRefs接收一个对象作为参数,遍历reactive对象的所有属性,使其成为ref对象,然后循环调用toRef
|
toRaw |
将响应式对象转化为普通对象。使用场景:不想改变视图时使用 通过 ReactiveFlags 枚举值 取出 proxy 对象的原始对象,脱离proxy对象 RAW = '__v_raw'
|
参考来源
小满教程 https://www.bilibili.com/video/BV1dS4y1y7vd
感谢小满,一键三连。