【Vue.js】Composition API - 进阶部分

116 阅读3分钟

和 ref 相关的 API 方法

shallowRef()

  • shallowRef() 是ref() 的浅层作用形式

注意

  • 和 ref() 不同,shallowRef() 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对 .value 的访问是响应式的。

应用场景

  • shallowRef() 常常用于对大型数据结构的性能优化或是与外部的状态管理系统集成。

triggerRef()

  • triggerRef() "强制触发"依赖于一个浅层 ref 的副作用,这通常在对浅引用的内部值进行深度变更后使用。
const shallow = shallowRef({
  greet: 'Hello, world'
});

// 触发该副作用第一次应该会打印 "Hello, world"
watchEffect(() => {
  console.log(shallow.value.greet)
});

// 这次变更不应触发副作用,因为这个 ref 是浅层的
shallow.value.greet = 'Hello, universe';

// 打印 "Hello, universe"
triggerRef(shallow);

customRef()

  • customRef() 是 Vue3 提供的一个自定义 ref 的高阶函数, 是一种显式声明对其依赖追踪和更新触发的控制方式。

官方文档给出的建议:

  • 一般来说,track() 应该在 get() 方法中调用,而 trigger() 应该在 set() 中调用。
  • 然而事实上,你对何时调用、是否应该调用他们有完全的控制权。
import { customRef } from 'vue';

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 {
  name: 'ComponentName',
  setup() {
    const cRef = useDebounceRef('abc');

    console.log(cRef);
  }
};
const cObjRef = useDebouncedRef({
  a: 1,
  b: 2,
  c: {
    d: {
      e: 'eee',
      f: ['f', 'f', 'f'],
      g: Symbol('ggg'),
    },
  },
});

console.log(cObjRef.value.c);

shallow 相关的 API 方法

shallowReactive()

  • reactive() 的浅层作用形式。
  • reactive() 不同,这里没有深层级的转换:一个浅层响应式对象里只有根级别的属性是响应式的。属性的值会被原样存储和暴露,这也意味着值为 ref 的属性不会被自动解包了。
    • 请谨慎使用此API

shallowReadonly()

  • readonly() 的浅层作用形式

  • readonly() 不同,这里没有深层级的转换:只有根层级的属性变为了只读。属性的值都会被原样存储和暴露,这也意味着值为 ref 的属性不会被自动解包了。

    • 请谨慎使用此API

raw 原始值转化

  • raw: 本义为生的, 在 Vue 中, raw 翻译成原始对象(非响应)更加恰当贴切

toRaw()

  • 根据一个 Vue 创建的代理返回其原始对象。

  • 作用域:

    • toRaw() 可以返回由 reactive()、readonly()、shallowReactive() 或者 shallowReadonly() 创建的代理对应的原始对象。

注意:

  • 这是一个可以用于临时读取而不引起代理访问/跟踪开销,或是写入而不触发更改的特殊方法。
  • 不建议保存对原始对象的持久引用,请谨慎使用。

markRaw()

  • 将一个对象标记为不可被转为代理(封印)。返回该对象本身。
  • markRaw是浅封印
const foo = markRaw({})
console.log(isReactive(reactive(foo))) // false

// 也适用于嵌套在其他响应性对象
const bar = reactive({ foo })
console.log(isReactive(bar.foo)) // false

组件作用域(Scope)相关的 API 方法

effectScope()

  • 创建一个 effect 作用域,可以捕获其中所创建的响应式副作用 (即计算属性和侦听器)
  • 这样捕获到的副作用可以一起处理。
const scope = effectScope();

// the scope which is created by invoking effectScope can use sub composition API outside this Component Model
scope.run(() => {
  console.log('do something');

  const state = reactive({ a: 1, b: 2, c: 3 });

  state.a = 11;

  const computeA = computed(() => state.a);

  console.log(computeA);

});

getCurrentScope()

  • getCurrentScope()用于判断当前环境是否有活跃的effect作用域并返回
function getCurrentScope(): EffectScope | undefined

onScopeDispose()

  • onScopeDispose() 在当前活跃的 effect 作用域上注册一个处理回调函数。当相关的 effect 作用域停止时会调用这个回调函数。
  • onScopeDispose() 可以理解成: 可复用的unmounted函数
  • onScopeDispose() 可以作为可复用的组合式函数中 onUnmounted 的替代品,它并不与组件耦合,因为每一个 Vue 组件的 setup() 函数也是在一个 effect 作用域中调用的。