重磅!!!Vue3中的响应式语法糖(官网更新)

最近,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,再不练你就废啦!

记得支持我哦,么么哒,祝您好事成双~~~~~~

猜你喜欢

转载自blog.csdn.net/Yan9_9/article/details/128917765