Reactive判断的API
只希望浅层的name进行响应式,对深层的name:kobe不响应
只对浅层的进行只读,深层的还是可以进行响应式
toRefs
export default{
setup(){
const info = reactive({
name:"why",
age:18
})
//将name和age从info中结构
let {name,age} = info
const changeAge = ()=>{
age++;
}
return{
name,
age,
changeAge
}
}
}
这时,age怎么点都不会++。 因为:let{name,age} = info 实际上等价于
let name = "why",let age = 18
这样就不是响应式的了,此时需要使用toRefs
let {name,age} = toRefs(info)等价于
{name:ref对象,age:ref对象}
结构出来的不是普通值,而是ref
所以在changeAge中: .value
const changeAge =()=>{
//age.value++
info.age++ 就和age.value等价了
}
toRef:只对一个其中一个属性进行转换ref,建立连接
const info = reactive({
name:"why",
age:18
})
只将info里的name进行ref转换,不能再给name加上结构{ }
let name = toref(info,"name")
ref其他的API(自定义Ref)
<template>
<div>
<input v-model = "message"/>
<h2>{{message}}</h2>
</div>
</template>
<script>
import {ref} from 'vue'
export default{
setup(){
const message = ref("Hello World")
return{
message
}
}
}
</script>
实际上message是一个ref对象,下面展示的实际上是我的依赖;
防抖:message变化的时候,下面变化的慢一些;需要使用自定义hook
//自定义一个自己的ref,而不是系统的ref
//ref:ref(..),所以需要传入一个value
import {customRef} from 'vue'
export default function(()=>{
//因为我每输入一个字符就要trigger更新一下依赖,如果我输入很多,他就会延迟N秒,但是我的效果是,整体输入完然后总共延迟1秒,所以一旦有输入,我就将上次输入后执行的定时器,清除掉
let timer = null;
//使用customRef后,返回的就不再是一个普通的Ref对象
return customRef((track,trigger)=>{
track:跟踪,收集依赖,调用依赖
trigger:什么时候触发依赖,进行更新
//需要返回一个对象,里面有set()和get()
return{
get(){
track();//收集最新依赖,发送
return value
},
set(newValue){
//取消上一次的定时器
clearTimeout(timer)
timer=setTimeout(()=>{
value = newValue;
trigger();更新所有触发依赖
},1000);
}
}
})
})
computed
<h2>{{fullName}}</h2>
import {ref,computed} from 'vue'
export default{
setup(){
const firstName = ref("abc")
const lastName = ref("cba")
//这样其实不是响应式的,需要计算属性
const fullName = firstName.value+..
//计算属性的写法:
//因为firstname是响应式的,当数据发生改变的时候会再执行一次getter回调,就会响应处最新值(响应式)
//computed返回值是一个ref对象
const fullName = computed(()=>{
firstName.value + lastName.value
})
计算属性完整写法
const fullName = computed({
get:()=>{
firstName.value + lastName.value
}
set(newValue){
}
})
return{
firstName,
lastName,
fullName,
}
}
}
侦听数据变化(watch)
<template>
<h2>{{name}}--{{age}}</h2>
<button @click = "changeName"></button>
<button @click = "changeAge"></button>
</template>
<script>
import {watchEffect,watch} from 'vue'
export default{
setup(){
//watchEffect会自动收集响应式依赖
const name=ref("why")
const age = ref(18)
const changeName = ()=>
name.value = "kobe"
const changeAge =() =>
age.value = 20
//默认打开页面会立马执行一次
watchEffect(()=>{
console.log(name.value)
以后每改变一次name的值,都会触发一次
如果里面不写,就谁也不会触发
在这里用谁的值,谁的对应依赖就会被添加,因此就会被监视到
})
return{
name,
age,
changeName,
changeAge
}
}
}
</script>
watchEffect的停止侦听
//watchEffect会返回一个stop函数
const stop = watchEffect(()=>{
console.log(name.value,age.value)
})
//当我的年龄>25时,我调用 停止侦听
//年龄会继续++,但是不会再侦听了
const changeAge =() =>{
age.value++
if(age.value>25){
stop()
}
}
watchEffect清除副作用
//此时会传入一个形参
const stop = watchEffect((onInvalidate)=>{
//根据name和age两个变量发送网络请求
/*当我的age发送网络请求的过程中,数据还没有请求回来
但是值已经发生了变化,一旦值发生了变化,就得再发一次新的请求。
这样会造成资源浪费。所以我们希望,我们改变值的时候,把上一次发送的请求取消掉,发送最新的请求。
上一次发送的网络请求就称为:副作用*/
//该形参可以被当成方法调用
onInvalidate(()=>{
//在这个函数中清除额外的副作用
request.cancel()
})
console.log(name.value,age.value)
})
const changeAge =() =>{
age.value++
if(age.value>25){
stop()
}
}
模拟网络请求
setup中使用ref
Vue可以在标签中设置`ref = "ref名"`属性.
在Vue中通过`this.$refs.ref名,来获取该标签的dom。
类似于原生dom中的`id = "id名
document.getElementsById("id名")`;
<h2 ref="title">哈哈哈</h2>
setup(){
//现在我们不写methods,怎么拿到呢?\
//这里的ref会被上方的默认赋值为title
const title = ref(null);
//这里是null,因为要等到h2被挂载后才可以
//console.log(title.value)
watchEffect(()=>{
console.log(title.value)
},{
pre:默认值,会提前执行(不写,默认执行这个)
flush:"pre"
post:等DOM执行完才会执行
flush:"post"
})
return{
title
}
},
methods:{
foo(){
//曾经我拿到哈哈哈,需要先绑定一个ref,然后通过$ref.title才能拿到值,title的值
this.$ref.title
}
}
Watch的使用
Watch可以拿到oldValue,WatchEffect就拿不到
export default{
setup(){
const info = reactive({
name:"why",
age:18
});
//第一种写法,只能侦听对象中的某个属性,传入getter函数写法
watch(()=>info.name,(newValue,oldValue)=>{
})
//第二种写法,传入一个可响应对象:ref对象
reactive对象获取到的newValue和oldValue的本身都是reactive对象
watch(info,(newValue,oldValue)=>{
})
// 如果希望newValue和oldValue是一个普通对象
// 写成getter函数,把info对象解构,此时这里是一个普通的对象,就会变成newValue和oldValue
watch(()=> {
return {...info}
},(newValue,oldValue)=>{
console.log
}
//ref对象获取到的newValue和oldValue是value值的本身
const name = ref("why")
watch(name,(newValue,oldValue)=>{
oldValue是why,newValue是coderwhy
直接是一个对象值本身,而不是一个对象形式
})
const changeData=()=>{
//name.value = "coderwhy"
info.name = "coderwhy"
}
return{
info,
changeData
}
}
}
侦听多个数据源
返回的是reactive对象,就是propx对象
不想他是reactive,而是真实的普通对象,那么需要解构一下
深度侦听
默认情况下,就是可以深度侦听。是reactive,源码默认开启deep;
普通对象就不可以深度侦听,因为他不是reactive
但是我就是想给普通对象深度侦听咋办呢?传入第三个参数deep