1)、功能:接受值,返回一个响应式的、可更改的 ref 对象,ref对象只有一个属性:value
。value属性保存着接受的值。
2)、使用ref对象:模板上不需要写 .value 属性(会自动解构),在js中,使用 .value 来完成数据的读写。
3)、ref可以接收基本类型和引用类型
ref可以接收基本类型。
ref也可以接收引用类型:如果将一个对象传给 ref函数,那么这个对象将通过 reactive() 转为具有深层次响应式的对象。
const count = ref(0) console.log(count.value) // 0 count.value++ console.log(count.value) // 1
示例
Document msg:{{msg}}
以后创建 非 对象类型的数据 使用 ref, 创建对象类型的数据建议使用 reactive
1)、功能: 接受一个对象,返回一个对象的响应式代理(proxy)。返回的对象以及其中嵌套的对象都会通过 ES Proxy 包裹,因此不等于源对象,建议只使用响应式代理,避免使用原始对象。
响应式转换是“深层”的:它会影响到所有嵌套的属性。一个响应式对象也将深层地解包任何 ref 属性,同时保持响应性。【解释一下”解包“,也就是说不用 .value。或者说读取ref属性时,自动会把.value属性的值拿到。】
2)、注意点:当访问到某个响应式数组或 Map
这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包【还得使用.value】。
创建一个响应式对象:
const obj = reactive({ count: 0 }) obj.count++
reactive示例:
Document person.name:{{person.name}}
person.sex:{{person.sex}}
person.age:{{person.age}}
person.wife.age:{{person.wife.age}}
book.name:{{book.name}}
book.price:{{book.price}}
book.author.age:{{book.author.age}}
msg:{{msg}}
Document countRef:{{countRef}}
personReactive.count:{{personReactive.count}}
当访问到某个响应式数组或 Map
这样的原生集合类型中的 ref 元素时,不会执行 ref 的解包(模板上也不会解包):
const books = reactive([ref('Vue 3 Guide'),ref(5)])//给reactive传入的是数组。不会解包 // 这里需要 .value console.log(books[0].value)//'Vue 3 Guide' console.log(books[1].value)//5 const map = reactive(new Map([['count', ref(0)]]))//给reactive传入的是Map。不会解包 // 这里需要 .value console.log(map.get('count').value)
示例:
Document
{{item.value}}
reactive 和 ref的选用:
对象用reactive,其它用ref
1)、功能:接受一个对象 (不论是响应式还是普通的) 或是一个 ref,返回一个原值的只读代理。
2)、只读代理是深层的:对任何嵌套属性的访问都将是只读的。它的 ref 解包行为与 reactive()
相同,但解包得到的值是只读的。
const original = reactive({ count: 0 }) const copy = readonly(original) watchEffect(() => { // 用来做响应性追踪 console.log(copy.count) }) // 更改源属性会触发其依赖的侦听器 original.count++ // 更改该只读副本将会失败,并会得到一个警告 copy.count++ // warning
示例:
Document bookReadonly.name:{{bookReadonly.name}}
bookReadonly.author.name:{{bookReadonly.author.name}}
原生中 const 只能让对象本身只读,不能让对象的属性(包括嵌套属性)只读。
但是,readonly可以让对象的属性(包括嵌套属性)只读
既就是:
const:限制的是:地址(变量对应内存的内容)是只读的。
readonly:限制的是:值(变量引用的内存区域)是只读的
功能:computed是计算属性。和选项式api中的计算属性实现的功能一样。
参数:
可以接受一个 getter 函数,返回一个只读的响应式 ref 对象。该 ref 通过 .value
暴露 getter 函数的返回值。
也可以接受一个带有 get
和 set
函数的对象来创建一个可写的 ref 对象。
const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // 错误
const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: (val) => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0
示例:
Document count:{{count}}
doubleCount:{{doubleCount}}
age:{{age}}
wifeAge:{{wifeAge}}
watch(第一个参数,第二个参数,第三个参数)
功能:侦听数据的变化,和选项式api中的watch实现的功能一样,组合式api中watch功能更加强大,灵活。默认是懒侦听的,即仅在侦听源发生变化时才执行回调函数。
参数:
第一个参数:侦听器的源,可以是以下几种:
一个函数(返回一个值的函数)
一个 ref
一个reactive
...或是由以上类型的值组成的数组
第二个参数:在(第一个参数的值)发生变化时要调用的回调函数。这个回调函数接受三个参数:新值、旧值,以及一个用于注册副作用清理(函数)的回调函数。该回调函数(副作用清理的函数)会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如:等待中的异步请求。
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值。
第三个参数:可选的, 是一个对象,支持以下这些选项:
immediate
:在侦听器创建时立即触发回调。第一次调用时旧值是 undefined
。
deep
:如果源是对象,侦听的源(是ref),强制深度遍历,以便在深层级变更时触发回调。参考深层侦听器。
返回值: 是个函数,该函数可以停止侦听。
与 watchEffect() 相比,watch()
使我们可以:
懒执行副作用;
更加明确是应该由哪个状态触发侦听器重新执行;
可以访问所侦听状态的前一个值和当前值。
示例
侦听一个 ref(侦听ref 不用写value):
const count = ref(0) watch(count, (count, prevCount) => { /* ... */ })
侦听一个 getter 函数:
const state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { /* ... */ } )
当侦听多个来源时,回调函数接受两个数组,分别对应来源数组中的新值和旧值:
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })
当使用 getter 函数作为源时,回调只在此函数的返回值变化时才会触发。如果你想让回调在深层级变更时也能触发,你需要使用 { deep: true }
强制侦听器进入深层级模式。在深层级模式时,如果回调函数由于深层级的变更而被触发,那么新值和旧值将是同一个对象。
const state = reactive({ count: 0 }) watch( () => state, (newValue, oldValue) => { // newValue === oldValue }, { deep: true } )
当直接侦听一个响应式对象时,侦听器会自动启用深层模式:
const state = reactive({ count: 0 }) watch(state, () => { /* 深层级变更状态所触发的回调 */ })
示例:
Document age:{{age}}
wifeAge:{{wifeAge}}
person.name:{{person.name}}
person.wife.name:{{person.wife.name}}
count:{{count}}
inc:{{inc}}
a:{{objReactive.a}}
b.b1:{{objReactive.b.b1}}
watchEffect
function watchEffect( effect: (onCleanup: OnCleanup) => void, options?: WatchEffectOptions ): StopHandle
功能: watchEffect也是监听数据,但是它会立即运行一个函数,而不是懒侦听。watchEffect侦听(依赖)的数据:watchEffect里使用了哪个数据,哪个数据就是watchEffect的依赖。watchEffect是深度侦听的。
参数:
第一个参数:要运行的副作用函数。这个副作用函数的参数也是一个函数,注册副作用清理的回调函数。该回调函数会在副作用下一次重新执行前调用,可以用来清除无效的副作用,例如:等待中的异步请求。(和watch的第二个参数中回调函数的第三参数一样)。
第二个参数:可选的选项,可以用来调整副作用的刷新时机或调试副作用的依赖。因为,侦听默认是在vue组件更新前调用,如果你希望组件更新后调用,可以把第二个参数传入:{ flush: 'post' }
返回值:用来停止该副作用的函数。
const count = ref(0) watchEffect(() => console.log(count.value)) // -> 输出 0 count.value++ // -> 输出 1
Document age:{{age}}
isAdult:{{isAdult}}
count:{{count}}
isLimit:{{isLimit}}
limitChina:{{limitChina}}
下面的示例,有点像防抖。
Document count:{{count}}
isLimit:{{isLimit}}
const stop = watchEffect(() => { console.log(count.value) }) // 当不再需要此侦听器时: const stopWatch = () => { stop() }
示例:
watchEffect p01的内容:{{msg}}
- 请求第一条数据
- 请求第二条数据
- 请求第三条数据
watchEffect没有具体监听哪一个值的变化,只要内部有某一个状态发生改变就会执行