reactive
、ref
、computed
、readonly
、watchEffect
、watch
六个响应式 API 的使用方法。
reactive
reactive
是 Vue 3.0
中提供的实现响应式数据的方法。在 Vue 2.0
中实现响应式数据是通过 Object
的 defineProPerty 属性来实现的,而在 Vue 3.0
中的响应式是通过 ES2015
的 Proxy 来实现。
reactive 参数必须是对象(json 或 Array)
响应式转换是“深层的”,会影响对象内部所有嵌套的属性。基于 ES2015
的 Proxy
实现,返回的代理对象不等于原始对象。建议仅使用代理对象而避免依赖原始对象。
<template>
<p>{{state.title}}</p>
</template>
<script>
import { reactive } from 'vue'
export default {
name:'App',
components: {
Test
},
setup() {
const state= reactive({title:'json'})
return {
state
}
}
}
</script>
<template>
<p>{{ state.title }}</p>
</template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
const state = reactive({
title: '十三'
})
setTimeout(() => {
state.title= '十六'
}, 2000)
return {
state
}
}
}
</script>
ref
和 reactive
一样,同样是实现响应式数据的方法。在业务开发中,我们可以使用它来定义一些简单数据
修改数据,可以通过 count.value = 1
类似这样的语法去修改
原因是 Vue 3.0
内部将 ref
悄悄的转化为 reactive
,如上述代码会被这样转换:
ref(0) => reactive({ value: 0 })
<template>
<p>{{count}}</p>
</template>
<script>
import { isRef, ref } from 'vue'
//模板内的变量是否为 ref 类型。判断类型也可以通过 isRef 方法
export default {
name:'App',
setup() {
const count =ref(0)
console.log(isRef(count))
return {
count
}
}
}
</script>
2://修改数据,可以通过 count.value = 1 类似这样的语法去修改
<template>
<p>{{count}}</p>
</template>
<script>
import { isRef, ref } from 'vue'
//模板内的变量是否为 ref 类型。判断类型也可以通过 isRef 方法
export default {
name:'App',
setup() {
const count =ref(0)
count.value=1
console.log(isRef(count))
return {
count
}
}
}
</script>
computed
Vue 2.0
时代,computed
作为选项出现在页面中,而到了 Vue 3.0
时代,它将会以钩子函数的形式出现。
<template>
<p>{{text}}</p>
</template>
<script>
import {reactive ,computed} from 'vue'
export default {
name:'App',
setup(){
const state=reactive({
name:'zt',
desc:'你好'
})
const text= computed(()=>{
console.log('11')
return state.name+state.desc
})
setTimeout(()=>{
state.name='zhengtao'
},2000)
return{
text
}
}
}
</script>
//上述代码通过 computed 函数将 name 和 desc 变量拼接,返回 text 渲染在模板上。
//2 秒后,name 变量将会被重新赋值,那么 computed 函数内带有 state.name,
所以会被动态计算,重新返回 text 值
readonly
readonly
顾名思义,用于创建一个只读的数据,并且所有的内容都是只读,不可修改
<template>
<p>{{ state.name }}</p>
<p>{{ state.desc }}</p>
<button @click="fn">修改</button>
</template>
<script>
import { reactive, computed, readonly } from 'vue'
export default {
name: 'App',
setup() {
const state = readonly({
name: '十三',
desc: '你好'
})
const fn = () => {
state.name = '十六'
state.desc = '他好'
console.log('state', state)
}
return {
state,
fn
}
}
}
</script>
watchEffect
首先 watchEffect
会追踪响应式数据的变化,并且还会在第一次渲染的时候立即执行
<template>
<div>
<h1>{{state.search}}</h1>
<button @click="handleSearch">改变查询字段</button>
</div>
</template>
<script>
import {reactive ,watchEffect } from 'vue'
export default {
setup(){
let state=reactive({
search:Date.now()
})
watchEffect(
()=>{
console.log(`监听${state.search}`)
}
)
const handleSearch=()=>{
state.search=Date.now()
}
return{
state,
handleSearch
}
}
}
</script>
watchEffect
函数返回一个新的函数,我们可以通过执行这个函数或者当组件被卸载的时候,来停止监听行为
setup() {
let timer = null
let state = reactive({
search: Date.now()
})
// 返回停止函数
const stop = watchEffect((onInvalidate) => {
console.log(`监听查询字段${state.search}`)
})
const handleSearch = () => {
state.search = Date.now()
}
setTimeout(() => {
console.log('执行 stop 停止监听')
stop() // 2 秒后停止监听行为
}, 2000)
return {
state,
handleSearch
}
}
atchEffect
的回调方法内有一个很重要的方法,用于清除副作用。它接受的回调函数也接受一个函数 onInvalidate
。重要的是它将会在 watchEffect
监听的变量改变之前被调用一次
<template>
<div>
<h1>{{state.search}}</h1>
<button @click="handleSearch">改变查询字段</button>
</div>
</template>
<script>
import { reactive,watchEffect } from 'vue'
export default {
setup(){
let state=reactive({
search:Date.now()
})
const stop=watchEffect(
(onInvalidate)=>{
console.log(`监听查询字段${state.search}`)
onInvalidate(
()=>{
console.log('执行 onInvalidate')
})
})
const handleSearch=()=>{
state.search=Date.now()
}
return {
state,
handleSearch
}
}
}
</script>
在 watchEffect 回调函数内,我用 setTimeout 的形式去模拟响应时间为 3 秒的异步请求,上面代码可以理解为 3 秒之内如果你不去改变 search 变量,那么页面就成功返回接口数据,如果在 3 秒之内你再次点击按钮改变了 search 变量,onInvalidate 将会被触发,从而清理掉上一次的接口请求,然后根据新的 search 变量去执行新的请求
<template>
<div>
<h1>{{state.search}}</h1>
<button @click="handleSearch">改变查询字段</button>
</div>
</template>
<script>
import {reactive,watchEffect} from 'vue'
export default {
setup(){
let timer=null
let state=reactive({
search:Date.now()
})
watchEffect(
(onInvalidate)=>{
console.log(`监听查询字段${state.search}`)
timer=setTimeout(
()=>{
console.log('模拟接口异步请求,3秒之后返回详情信息')
},3000)
onInvalidate(
()=>{
console.log('清除');
clearInterval(timer);
})
}
)
const handleSearch=()=>{
state.search=Date.now()
}
return {
state,
handleSearch
}
}
}
</script>
watch
watch
的功能和之前的 Vue 2.0
的 watch
是一样的。和 watchEffect
相比较,区别在 watch
必须制定一个特定的变量,并且不会默认执行回调函数,而是等到监听的变量改变了,才会执行。并且你可以拿到改变前和改变后的值
<template>
<div>
<h1>{{state.search}}</h1>
<button @click="handleSearch">改变查询字段</button>
</div>
</template>
<script>
import { reactive, watch } from "vue"
export default{
setup() {
let timer=null
let state=reactive({
search:Date.now()
})
watch(
()=>{
return state.search
},(nextData,preData)=>{
console.log('preData',preData)
console.log('nextData',nextData)
}
)
const handleSearch=()=>{
state.search=Date.now()
}
return {
state,
handleSearch
}
}
}
</script>