[TOC] >[success] # 其他 Api 使用 >[info] ## isRef ~~~ 1.检查值是否为一个 ref 对象。返回值是一个boolean 类型 ~~~ >[info] ## unref ~~~ 1.如果参数是一个 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val 的语法糖函数。 function useFoo(x: number | Ref<number>) { const unwrapped = unref(x) // unwrapped 现在一定是数字类型 } ~~~ >[info] ## toRef ~~~ 1.可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接,简单的说将一个对象的中的一个属性变成ref对象,并且会相互影响 2.官方的案例说明 const state = reactive({ foo: 1, bar: 2 }) const fooRef = toRef(state, 'foo') fooRef.value++ console.log(state.foo) // 2 state.foo++ console.log(fooRef.value) // 3 3.注意说明如果是直接使用ref 那么会 拷贝了一份新的数据值单独操作, 更新时相互不影响举个例子 const state = reactive({ foo: 1, bar: 2 }) // 如果执行foo2.value++ foo和state中的数据不会更新 const foo2 = ref(state.foo) 4.下面案例还发现"const t = toRef(obj,'t') // t.value => undefined" 即使源 property 不存在,toRef 也会返回一 个可用的 ref ('在使用可选 prop 时特别有用,可选 prop 并不会被 toRefs 处理') ~~~ >[danger] ##### 案例 ~~~ 1.点击后页面和的打印的显示都是100,说明无论是普通对象 还是ref对象 还是reactive返回的proxy对象, 他们通过toRef 取出源响应式对象上的某个 property 都会互相关联作用 ~~~ ~~~ <template> <div> {{t}}--{{val}} -- {{age}} <button @click="change">测试</button> </div> </template> <script lang="ts"> import { toRef ,reactive, ref} from 'vue' export default { setup() { const count = ref(0) const obj:{name:string,age:number,t?:any} = reactive({ age:18, name:"w" }) const comObj = { age:18 } const t = toRef(obj,'t') // t.value => undefined const val = toRef(count, 'value') const age = toRef(comObj,'age') const change = ()=>{ t.value = 100 val.value = 100 age.value = 100 console.log(obj.t,count.value,comObj.age) } return { t,val,age,change } } } </script> ~~~ >[info] ## toRefs ~~~ 1.'toRef' 是将对象的指定属性中指定值转换ref对象,'toRefs' 把一个响应式对象转换成普通对象,该普通对象的 每个 property 都是一个 ref,其余特点和toRef 一样都是会和源相互关联 const state = reactive({ foo: 1, bar: 2 }) const stateAsRefs = toRefs(state) /* stateAsRefs 的类型: { foo: Ref<number>, bar: Ref<number> } */ // ref 和原始 property 已经“链接”起来了 state.foo++ console.log(stateAsRefs.foo.value) // 2 stateAsRefs.foo.value++ console.log(state.foo) // 3 2.关于使用场景在解构的时候reactive 被包裹的对象解构后使用的单个属性变成非响应式,可以利用toRefs 或者当从合成函数返回响应式对象时,toRefs 非常有用,这样消费组件就可以在不丢失响应式的情况下对返回 的对象进行分解使用 ~~~ >[danger] ##### 案例一 ~~~ <template> <div> <!-- 没有使用toRefs setup返回值{obj} 在模板需要obj.age使用 --> {{age}} <button @click="change">测试</button> </div> </template> <script lang="ts"> import { toRefs ,reactive} from 'vue' export default { setup() { const obj:{name:string,age:number,t?:any} = reactive({ age:18, name:"w" }) const toRefsObj = toRefs(obj) const change = ()=>{ obj.age ++ // toRefsObj.age.value ++ } return { ...toRefsObj, change } } } </script> ~~~ >[danger] ##### 案例二 ~~~ function useFeatureX() { const state = reactive({ foo: 1, bar: 2 }) // 操作 state 的逻辑 // 返回时转换为ref return toRefs(state) } export default { setup() { // 可以在不失去响应性的情况下解构 const { foo, bar } = useFeatureX() return { foo, bar } } } ~~~ >[info] ## customRef -- 自定义ref ~~~ 1.创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。它需要一个工厂函数,该函数接收 track 和 trigger 函数作为参数,并且应该返回一个带有 get 和 set 的对象。简单说创建一个自己可以控制的 'ref' ~~~ >[danger] ##### 官网的防抖函数案例 ~~~ <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() { return { text: useDebouncedRef('hello') } } } ~~~ >[info] ## shallowRef ~~~ 1.创建一个跟踪自身 .value 变化的 ref,但不会使其值也变成响应式的 const foo = shallowRef({}) // 改变 ref 的值是响应式的 foo.value = {} // 但是这个值不会被转换。 isReactive(foo.value) // false ~~~ >[danger] ##### 案例 ~~~ <template> <div> {{count}} <button @click="change">测试</button> </div> </template> <script lang="ts"> import { shallowRef,reactive } from 'vue' export default { setup() { let count = shallowRef<any>(0) const change = ()=>{ count.value ="w" console.log(count) // ref 对象 count = {} console.log(count) // 普通空对象如果是ref 声明此时是proxy对象 } return { count, change } } } </script> ~~~ >[info] ## truggerRef ~~~ 1.手动执行与 shallowRef 关联的任何副作用。 const shallow = shallowRef({ greet: 'Hello, world' }) // 第一次运行时记录一次 "Hello, world" watchEffect(() => { console.log(shallow.value.greet) }) // 这不会触发副作用,因为 ref 是浅层的 shallow.value.greet = 'Hello, universe' // 记录 "Hello, universe" triggerRef(shallow) ~~~ >[danger] ##### 案例 ~~~ 1.下面案例" shallow.value.greet='zz'" 直接使用视图不会更新的因为使用了shallowRef,此时的ref对象 是浅层的,但是如果直接不深层改动而是直接改动整value属性的值"shallow.value ={greet:'zz'} " 视图会 更改,此时非要" shallow.value.greet='zz'" 这种形式也更改需要使用'triggerRef' 配合 ~~~ ~~~ <template> <div> {{shallow.greet}} <button @click="change">测试</button> </div> </template> <script lang="ts"> import { shallowRef,reactive,triggerRef } from 'vue' export default { setup() { const shallow = shallowRef({ greet: 'Hello, world' }) console.log(shallow); const change = ()=>{ // shallow.value ={greet:'zz'} shallow.value.greet='zz' console.log(shallow); // triggerRef(shallow) 手动执行与 shallowRef 关联的任何副作用 } return { shallow, change } } } </script> ~~~ >[danger] ##### 更多 [看不动了标记一下](https://v3.cn.vuejs.org/api/basic-reactivity.html#readonly)