Vue3关于响应式数据类型详解(ref、reactive、toRef、及toRefs)

目录
  • ref
  • reactive
  • toRef()
  • toRefs()

ref

接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的 property .value。

类型

function ref<T>(value: T): Ref<UnwrapRef<T>>

interface Ref<T> {
  value: T
}

详细信息

ref 对象是可更改的,也就是说你可以为 .value 赋予新的值。它也是响应式的,即所有对 .value 的操作都将被追踪,并且写操作会触发与之相关的副作用。
如果将一个对象赋值给 ref,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。这也意味着如果对象中包含了嵌套的 ref,它们将被深层地解包。
若要避免这种深层次的转换,请使用 shallowRef() 来替代

示例

import { ref } from 'vue
const count = ref<number>(0)
console.log(count.value) // 0
count.value++
console.log(count.value) // 1

reactive

返回一个对象的响应式代理

类型

function reactive<T extends object>(target: T): UnwrapNestedRefs<T>

详细信息

响应式转换是“深层”的:它会影响到所有嵌套的 property。一个响应式对象也将深层地解包任何 ref property,同时保持响应性。

值得注意的是,当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包。

若要避免深层响应式转换,只想保留对这个对象顶层次访问的响应性,请使用 shallowReactive() 作替代。

返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹,因此不等于源对象,建议只使用响应式代理,避免依赖于原始对象。

示例

import { reactive } from 'vue'
interface Obj {
  count: number
}
const obj = reactive<Obj>({ count: 0 })
obj.count++

ref 的解包:

const count = ref(1)
const obj = reactive({ count })

// ref 会被解包
console.log(obj.count === count.value) // true

// 会更新 `obj.count`
count.value++
console.log(count.value) // 2
console.log(obj.count) // 2

// 也会更新 `count` ref
obj.count++
console.log(obj.count) // 3
console.log(count.value) // 3

注意当访问到某个响应式数组或 Map 这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包

const books = reactive([ref('Vue 3 Guide')])
// 这里需要 .value
console.log(books[0].value)

const map = reactive(new Map([['count', ref(0)]]))
// 这里需要 .value
console.log(map.get('count').value)

将一个 ref 赋值给为一个 reactive 属性时,该 ref 会被自动解包:

const count = ref(1)
const obj = reactive({})

obj.count = count

console.log(obj.count) // 1
console.log(obj.count === count.value) // true

toRef()

可用于为响应式对象上的 property 创建 ref。这样创建的 ref 与其源 property 保持同步:改变源 property 将更新 ref,反之亦然。

类型

function toRef<T extends object, K extends keyof T>(
  object: T,
  key: K,
  defaultValue?: T[K]
): ToRef<T[K]>

type ToRef<T> = T extends Ref ? T : Ref<T>

示例

const state = reactive({
  foo: 1,
  bar: 2
})
const fooRef = toRef(state, 'foo')
// 更改该 ref 会更新源属性
fooRef.value++
console.log(state.foo) // 2
// 更改源属性也会更新该 ref
state.foo++
console.log(fooRef.value) // 3

请注意,这不同于:

const fooRef = ref(state.foo)
//上面这个 ref 不会和 state.foo 保持同步,因为这个 ref() 接收到的是一个纯数值。

//toRef() 这个函数在你想把一个 prop 的 ref 传递给一个组合式函数时会很有用
<script setup>
import { toRef } from 'vue'

const props = defineProps(/* ... */)

// 将 `props.foo` 转换为 ref,然后传入
// 一个组合式函数
useSomeFeature(toRef(props, 'foo'))
</script>

当 toRef 与组件 prop 结合使用时,关于对 prop 做出更改的通用限制依然有效。尝试将新的值传递给 ref 等效于尝试直接更改 prop,这是不允许的。在这种场景下,你可能可以考虑使用带有 get 和 set 的 computed 替代。

即使源 property 当前不存在,toRef() 也会返回一个可用的 ref。这让它在处理可选 prop 的时候格外实用,而可选 prop 在使用 toRefs 时不会被保留。

toRefs()

将一个响应式对象转换为一个普通对象,这个普通对象的每个 property 都是指向源对象相应 property 的 ref。每个单独的 ref 都是使用 toRef() 创建的。

类型

function toRefs<T extends object>(
  object: T
): {
  [K in keyof T]: ToRef<T[K]>
}

type ToRef = T extends Ref ? T : Ref<T>

示例

const state = reactive({
  foo: 1,
  bar: 2
})

const stateAsRefs = toRefs(state)
/*
stateAsRefs 的类型:{
  foo: Ref<number>,
  bar: Ref<number>
}
*/

// 这个 ref 和源属性已经“链接上了”
state.foo++
console.log(stateAsRefs.foo.value) // 2

stateAsRefs.foo.value++
console.log(state.foo) // 3

当从组合式函数中返回响应式对象时,toRefs 大有作为,使用它,消费者组件可以解构/扩展返回的对象而不会失去响应性:

function useFeatureX() {
  const state = reactive({
    foo: 1,
    bar: 2
  })

  // ...基于状态的操作逻辑

  // 在返回时都转为 ref
  return toRefs(state)
}

// 可以解构而不会失去响应性
const { foo, bar } = useFeatureX()

toRefs 在调用时只会为源对象上可以列举出的 property 创建 ref。如果要为可能还不存在的 property 创建 ref,请改用 toRef 。

到此这篇关于Vue3关于响应式数据类型(ref、reactive、toRef、以及toRefs)的文章就介绍到这了,更多相关Vue3响应式数据类型内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Vue3关于响应式数据类型详解(ref、reactive、toRef、及toRefs)

    目录 ref reactive toRef() toRefs() ref 接受一个内部值,返回一个响应式的.可更改的 ref 对象,此对象只有一个指向其内部值的 property .value. 类型 function ref<T>(value: T): Ref<UnwrapRef<T>> interface Ref<T> { value: T } 详细信息 ref 对象是可更改的,也就是说你可以为 .value 赋予新的值.它也是响应式的,即所有对 .va

  • vue3的ref,computed,reactive和toRefs你都了解吗

    目录 1.ref 2.computed 3.reactive 4.toRefs 总结 在vue2中,data函数里返回的值直接为响应式的,但在vue3中我们需要使用一些函数才能达到这个效果. setup函数中拿不到vue的this 1.ref 本质为一个函数,输入参数为一个值(原始类型),返回响应式的对象 2.computed 本质为一个函数,输入参数是一个函数,可以将我们需要的值作为输入函数的返回值 例子:实现点击按钮,屏幕上的数加1 <template> <div id='app'&

  • 浅谈vue3中ref、toRef、toRefs 和 reactive的区别

    目录 一.ref——定义任意类型响应式数据 二.reactive——定义响应式对象 三.toRef——将一个 reactive 转化为一个 ref 四.toRefs——将多个 reactive 自动解构为多个 ref 一.ref——定义任意类型响应式数据 ref 能定义“任何类型”的响应式数据(ref 在 vue3 中指响应式数据). 参数可以传入任意数据类型. 使用 ref 定义的属性必须通过 .value 的形式才能修改其值.属性的值一旦被修改就会触发模板的重新渲染以显示最新的值. 对于在

  • vue3如何定义变量及ref、reactive、toRefs特性说明

    目录 vue3定义变量及ref.reactive.toRefs特性 1.ref() 函数 2.reactive() 函数 3.toRefs() 函数 vue3定义变量 1.const 声明变量 2.reactive和ref 3.provide与inject vue3定义变量及ref.reactive.toRefs特性 1.ref() 函数 ref() 函数用来根据给定的值创建一个响应式的数据对象,传入的为基本数据类型,例如字符串.数字.boolean 等,返回值是一个对象,这个对象上只包含一个

  • vue3中defineProps传值使用ref响应式失效详解

    子组件接收父组件的传参. 父组件: <template> <Son :data="data"/> </template> <script setup> import { ref } from "vue"; let data = ref('hello') setTimeout(() => { data.value = 'how are you doing' }, 2000) </script> 子组件:

  • Vue3.0数据响应式原理详解

    基于Vue3.0发布在GitHub上的第一版源码(2019.10.05)整理 预备知识 ES6 Proxy,整个响应式系统的基础. 新的composition-API的基本使用,目前还没有中文文档,可以先通过这个仓库(composition-api-rfc)了解,里面也有对应的在线文档. 先把Vue3.0跑起来 先把vue-next仓库的代码clone下来,安装依赖然后构建一下,vue的package下的dist目录下找到构建的脚本,引入脚本即可. 下面一个简单计数器的DEMO: <!DOCTY

  • Vue响应式原理详解

    Vue 嘴显著的特性之一便是响应式系统(reactivity system),模型层(model)只是普通JavaScript对象,修改它则更新视图(view). Vue 响应式系统的底层细节 如何追踪变化 把一个普通的JavaScript对象传给Vue实例的data选项,Vue将遍历此对象的所有属性,并使用Object.defineProperty 把这些属性全部转为 getter/setter.Object.defineProperty是仅ES5支持,并无法shim的特性,这也就是为什么Vu

  • Bootstrap响应式表格详解

    Bootstrap 的响应式 CSS 能够自适应于台式机.平板电脑和手机 下面是手机端显示的样式 代码如下: 1.test.php <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>无标题文档</title> <link type="text/css"

  • 几种响应式文字详解

    讲真,其实我也不知道该如何为此篇开头, 因为响应式文字需不需要做其实我也没有深入探究过, 但在学习其他网站的过程中,我发现了一些比较新奇的做法,所以想试着梳理一下, 为何会出现这种有些奇怪,可能实则非常奇妙的解决方案. 如果理解有偏差的地方,还望大佬们不吝赐教. 简单来说,响应式是为了让网页在各种显示设备上都有不错的浏览体验, 无论是 @media 将元素换行,后台获取 userAgent 返回不同页面,利用 viewport 限定视图,还是利用根元素 html 属性来计算大小等, 他们都能实现

  • Template ref在Vue3中的实现原理详解

    目录 背景 模板的编译 setup 函数返回值的处理 组件的渲染 Template Ref 的注册 总结 背景 最近我的 Vue3 音乐课程后台问答区频繁出现一个关于 Template ref 在 Composition API 中使用的问题,于是我就想写一篇文章详细解答这个问题. 先来看一个简单的例子: <template> <div ref="root">This is a root element</div> </template>

  • 40行代码把Vue3的响应式集成进React做状态管理

    前言 vue-next是Vue3的源码仓库,Vue3采用lerna做package的划分,而响应式能力@vue/reactivity被划分到了单独的一个package中. 如果我们想把它集成到React中,可行吗?来试一试吧. 使用示例 话不多说,先看看怎么用的解解馋吧. // store.ts import { reactive, computed, effect } from '@vue/reactivity'; export const state = reactive({ count:

  • Vue3 计算属性的用法详解

    目录 computed 计算属性说明 计算属性使用 总结 注意 上一篇博文说了 vue3 项目的 toRefs 函数和 toRef 函数,今天就稍微总结一下 vue3 的计算属性,其实学过 vue2 的宝子们应该都清楚,计算属性这个东西在项目开发过程中使用的还是比较频繁的,使用频率相对来说比较高,所以说咱今天稍微总结一下 vue3 项目中的计算属性,下面开始. computed 计算属性说明 computed 表示计算属性,通常的作用是用来进行数据处理,方便在末班中简化书写. 比如日常在模板中我

  • Vue3中watch的使用详解

    目录 Vue3中watch的详解 Vue2使用watch Vue3使用watch 情况1 情况2 情况3 情况4 情况5 特殊情况 Vue3中watch的详解 Vue2使用watch <template> <div>总合:{{ sum }}<button @click="sum++">点击累加</button></div> </template> <script> import { ref } from

随机推荐