最近,vue的官网更新了,主要是推出了些关于响应式的优化方案。
下面是这次官网更新知识点的总结。
1.语法糖--响应式变量$ref()
之前我们都是使用ref()来定义一个简单的响应式数据,但是使用的时候需要不停地.value,会造成比较繁琐。
$ref()就解决了这个问题。
栗子:
let count=$ref(0) //使用$ref()定义数据
function increment() {
count++ //此处就不需要再count.value了
}
其实,$ref()的使用就是这么简单,我们只需要注意:
每一个会返回 ref 的响应式 API ($ref、$computed等)都有一个相对应的、以 $ 为前缀的宏函数。
如下:
2.通过$()解构
我们都知道,reactive定义的数据, 当遇到解构/直接赋值时,响应式都会丢失!!!
针对ref/reactive的结构丢失响应式的弊病,推出了$()。
栗子1:hooks解构出的响应式
//引入自定义的hooks函数
import { useMouse } from '@vueuse/core'
//解构出x,y 并且使用$()包裹赋予响应式。
const { x, y } = $(useMouse())
//这样解构出来的x,y都是响应式的了。
console.log(x, y)
//注意:
x 如果已经是一个 ref,则会简单地返回它本身,而不会再创建新的 ref。
如果一个被解构的值不是 ref (例如是一个函数),也仍然可以使用,这个值会被包装进一个 ref,因此其他代码都会正常工作。
响应式props解构
<script setup> 中对 defineProps 的使用有两个痛点:
1.为了保持响应性,你始终需要以 props.x 的方式访问这些 prop。这意味着你不能够解构 defineProps 的返回值,因为得到的变量将不是响应式的、也不会更新。
2.
当使用 基于类型的 props 的声明时,无法很方便地声明这些 prop 的默认值。为此我们提供了 withDefaults() 这个 API,但使用起来仍然很笨拙。
当 defineProps 与解构一起使用时,我们可以通过应用编译时转换来解决这些问题,
栗子:
<script setup lang="ts">
//定义props的类型
interface Props {
msg: string
count?: number
foo?: string
}
//从defineProps中解构值,并且默认赋值可以使用,解构时起别名也可以使用。
const {
msg,
// 默认值正常可用
count = 1,
// 解构时命别名也可用
// 这里我们就将 `props.foo` 命别名为 `bar`
foo: bar
} = defineProps<Props>()
//监听打印
watchEffect(() => {
// 会在 props 变化时打印
console.log(msg, count, bar)
})
</script>
3.$ref()语法糖出现的问题
虽然响应式变量使我们可以不再受 .value 的困扰,,但它也使得我们在函数间传递响应式变量时可能造成“响应性丢失”的问题。如下:
丢失响应式--
场景一:以参数形式传入函数
//此处x是限制了个Ref类型,并且又需要是number类型的参数
function trackChange(x: Ref<number>) {
watch(x, (x) => {
console.log('x 改变了!')
})
}
//定义一个响应式对象
let count = $ref(0)
//传入count错误
trackChange(count) // 无效!
//分析原因:
1.因为在执行trackChange(count)的时候,
其实代码被编译成了:trackChange(count.value)
2.这里的 count.value 是以一个 number 类型值的形式传入,然而 trackChange 期望接收的是一个真正的 ref,所以传入的类型错误。
场景二:作为函数返回值
//如果将响应式变量直接放在返回值表达式中会丢失掉响应性:
function useMouse() {
let x = $ref(0)
let y = $ref(0)
// 不起效!
return {x,y}
}
//分析原因:
1.上面的语句实际上被编译为了:
return {
x: x.value,
y: y.value
}
2.实际上是把一个number类型的值返回出去了,而不是返回真正的 ref。
那么,针对这两个场景就出现了$$()
4.保持在函数间传递时的响应式--$$()
针对以上丢失响应式的场景,vue推出了$$()来解决,我们先看场景一的解决方案。
解决场景一:
let count = $ref(0)
//trackChange(count) 此处不要再这样了
//而是变成$$()进行包裹,
++ trackChange($$(count))
//$$() 的效果就像是一个转义标识:$$() 中的响应式变量不会追加上 .value。
解决场景二:
function useMouse() {
let x = $ref(0)
let y = $ref(0)
// 返回的时候用$$()进行包裹,,修改后起效
return $$({
x,
y
})
}
//$$() 调用时任何对响应式变量的引用都会保留为对相应 ref 的引用
在已解构的 props 上使用 $$()
$$() 也适用于已解构的 props,因为它们也是响应式的变量。
//定义声明props
const { count } = defineProps<{ count: number }>()
//使用$$()对结构出的props进行包裹
passAsRef($$(count))
5.注意:响应式语法糖需要显示的开启!!!
5.1 Vite中-- 在vite.config.js中开启
// vite.config.js
export default {
plugins: [
vue({
reactivityTransform: true
})
]
}
5.2 TS的集成--env.d.ts中开启
如果您还使用了TS,那么也需要在TS中显示的开启。
<reference types="vue/macros-global" />
PS:若你是从 vue/macros 中显式引入宏函数时,则不需要像这样全局声明。
抓紧时间练起来吧,兄dei,再不练你就废啦!
记得支持我哦,么么哒,祝您好事成双~~~~~~