🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
>[danger] ##### toRaw -- 返回 reactive 或 readonly 代理的原始对象 1. 可以返回由[`reactive()`](https://cn.vuejs.org/api/reactivity-core.html#reactive)、[`readonly()`](https://cn.vuejs.org/api/reactivity-core.html#readonly)、[`shallowReactive()`](https://cn.vuejs.org/api/reactivity-advanced.html#shallowreactive)或者[`shallowReadonly()`](https://cn.vuejs.org/api/reactivity-advanced.html#shallowreadonly),对`ref`无效,官网给的建议这是一个**逃生舱**,**可用于临时读取数据而无需承担代理访问/跟踪的开销,也可用于写入数据而避免触发更改**,不建议保留对原始对象的持久引用。请谨慎使用。 2. 简单理解获取**reactive()、readonly()、shallowReactive() 或者 shallowReadonly()** 包裹的原生对象,更改原始对象不会触发视图更新 ~~~ export default { name: 'App', setup() { const info = { name: 'W' } const refInfo = ref(info) const reactiveInfo = reactive(info) const readonlyInfo = readonly(info) const refNum = ref(1) console.log( toRaw(refNum), // 不会转换 toRaw(refInfo), // 不会转换 toRaw(reactiveInfo), // 获取代理对象 toRaw(readonlyInfo) // 获取代理对象 ) // 说明toRaw 获取的是readonly 代理的目标对象 console.log(toRaw(readonlyInfo) === info) // true return {} }, } ~~~ >[danger] ##### shallowReactive -- 创建一个浅层响应式代理 1. 创建一个响应式代理,它跟踪其自身 属性的响应性,但不执行嵌套对象的深层响应式转换 (深层还是原生对象)。 2. 与 `reactive `不同,任何使用 `ref `的 属性都不会被**代理自动解包**,也就是说`ref `作为对象`value `时候并不会像`reactive `那样将不使用`vualue `属性直接调用 ~~~ const state = shallowReactive({ foo: 1, nested: { bar: 2 } }) // 改变 state 本身的性质是响应式的 state.foo++ // ...但是不转换嵌套对象 isReactive(state.nested) // false state.nested.bar++ // 非响应式 ~~~ >[danger] ##### shallowReadonly -- 创建一个浅层响应式代理只读 1. 创建一个 `proxy`,使其自身的 属性为只读,但不执行嵌套对象的深度只读转换(**深层还是可读、可写的**)。 2. 与 `reactive `不同,任何使用 `ref `的 属性都不会被**代理自动解包**,也就是说`ref `作为对象`value `时候并不会像`reactive `那样将不使用`vualue `属性直接调用 ~~~ const state = shallowReadonly({ foo: 1, nested: { bar: 2 } }) // 改变 state 本身的 property 将失败 state.foo++ // ...但适用于嵌套对象 isReadonly(state.nested) // false state.nested.bar++ // 适用 ~~~ >[danger] ##### unref 1. 如果参数是一个 ref,则返回内部值,否则返回参数本身。这是 `val = isRef(val) ? val.value : val` 的语法糖函数。 ~~~ function useFoo(x: number | Ref<number>) { const unwrapped = unref(x) // unwrapped 现在一定是数字类型 } ~~~ >[danger] ##### shallowRef 和 triggerRef 1. `shallowRef`创建一个**浅层的ref对象**; 2. `triggerRef`手动触发和 `shallowRef `相关联的副作用 * 案例一 ~~~ 1. 因为shallowRef 包裹的会生成浅层的'ref' 对象因此最外层此时还是具有响应式页面一秒后的变化如图 ~~~ ![](https://img.kancloud.cn/eb/9a/eb9a3404d1b56a4dff781146628ad95e_198x37.png) ~~~html <template> <div>{{ refName }} -- {{ sRefName }}</div> </template> <script> import { shallowRef, ref } from 'vue' export default { name: 'App', setup() { const refName = ref(1) const sRefName = shallowRef(1) setTimeout(() => { refName.value = 1000 sRefName.value = 10001 }, 1000) console.log(refName, sRefName) return { refName, sRefName, } }, } </script> <style></style> ~~~ * 案例二 -- shallowRef 深层效果 ~~~ 1.当'shallowRef' 值换成对象时候发现此时页面不再是响应式的了,一秒后如图 ~~~ ![](https://img.kancloud.cn/2d/35/2d35f2e4498422614b282b71e96117a5_290x82.png) ~~~ html <template> <!-- {{ refName }} -- --> <div>{{ sRefName }}</div> </template> <script> import { shallowRef } from 'vue' export default { name: 'App', setup() { // const refName = ref({ name: 'w' }) const sRefName = shallowRef({ name: 'w' }) setTimeout(() => { // refName.value.name = 1000 sRefName.value.name = 1000 }, 1000) // console.log(refName, sRefName) return { // refName, sRefName, } }, } </script> <style></style> ~~~ 将上面代码注释都放开 通过console 打印就可以发现深层对象并没有被代理 ![](https://img.kancloud.cn/17/8d/178d89c6692db4d1022040fb0773a834_1176x297.png) * 案例三 使用'triggerRef'手动触发和 shallowRef 相关联的副作用 ~~~ 1.当想让其具备响应式时候通过'triggerRef' 配合,1s 后结果 2.其实不用使用'triggerRef' 也可以只要吧案例二中注释去掉,因为ref 触发内部自己调用的triggerRef,因此也 变相的刷新页面从而触发了'shallowRef ' ~~~ ![](https://img.kancloud.cn/36/fe/36fe85b72f0c39be5c5d80cfd8da4cd2_203x72.png) ~~~ <template> <!-- {{ refName }} -- --> <div>{{ sRefName }}</div> </template> <script> import { shallowRef, triggerRef } from 'vue' export default { name: 'App', setup() { // const refName = ref({ name: 'w' }) const sRefName = shallowRef({ name: 'w' }) setTimeout(() => { // refName.value.name = 1000 sRefName.value.name = 1000 triggerRef(sRefName) }, 1000) // console.log(refName, sRefName) return { // refName, sRefName, } }, } </script> <style></style> ~~~ >[danger] ##### customRef -- 赖项跟踪和更新触发进行显式控制 ~~~ 1.创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制: 2.它需要一个工厂函数,该函数接受 track 和 trigger 函数作为参数;并且应该返回一个带有 get 和 set 的对象; 简单说创建一个自己可以控制的'ref' 3.下面案例因为可以控制响应时机一次做了一防抖决定什么时候进行渲染 ~~~ * 官网的防抖函数案例 ~~~ <input v-model="text" /> ~~~ ~~~ function useDebouncedRef(value, delay = 200) { let timeout return customRef((track, trigger) => { return { get() { track() return value }, set(newValue) { clearTimeout(timeout) timeout = setTimeout(() => { value = newValue trigger() }, delay) } } }) } export default { setup() { const text = useDebouncedRef('hello') // 是一个ref 对象 return { text } } } ~~~ >[danger] ##### markRaw 1. 将一个对象标记为不可被转为代理。返回该对象本身。 ~~~ const foo = markRaw({}) console.log(isReactive(reactive(foo))) // false // 也适用于嵌套在其他响应性对象 const bar = reactive({ foo }) console.log(isReactive(bar.foo)) // false ~~~ ~~~ const foo = markRaw({ nested: {} }) const bar = reactive({ // 尽管 `foo` 被标记为了原始对象,但 foo.nested 却没有 nested: foo.nested }) console.log(foo.nested === bar.nested) // false ~~~