0


vue3响应式用法(高阶性能优化)

文章目录

在这里插入图片描述

前言:

翻别人代码时,总结发现极大部分使用

vue3

的人只会用

ref

reactive

处理响应式数据无论什么场景都是,但

vue官方

针对某些应用场景有其它的更好用的

响应式api

实现响应式,从而达到更好的性能效果。例如深层的树状数据结构可以通过

shallowRef

实现浅层响应式,不会被深层递归地转为响应式。本文通过例子详细总结几种

vue3

响应式的高阶用法。

一、 shallowRef()

简述:

ref

的浅层作用形式。

shallowRef

与普通的

ref

的区别在于,

shallowRef

不会对对象进行深度的响应式处理,也就是

shallowRef

包含的对象内部的属性发生变化时,

shallowRef

本身不会触发重新渲染或响应式更新,所以使用

shallowRef

时只关心顶层的引用变化。

代码示例:

<script lang="ts" setup>
  import { shallowRef } from 'vue';

  const data = shallowRef({ name: '天天鸭', age: 18 });

  // 修改顶层引用会触发响应式更新
  data.value = { name: 'Bob', age: 20 };

  // 修改内部属性不会触发响应式更新
  data.value.age = 30;
</script>

作为性能优化的一种手段,当业务场景中有大量复杂数据结构但只有顶层引用需要响应式时就非常有用,但你需要更加注意对象的更新逻辑,确保在需要时正确地应用响应式转换。

二、 triggerRef()

简述:用于强制执行依赖于

shallowRef

的副作用。也就是说当使用

shallowRef

响应式时只能修改顶层数据,但特殊情况使用

triggerRef

可以强制修改内层属性,大大提高灵活性。

代码示例:

<script lang="ts" setup>
  import { shallowRef, triggerRef } from 'vue';

  const data = shallowRef({ name: '天天鸭', age: 18 });

  // 修改内部属性不会触发响应式更新
  data.value.age = 30;

  // 但这里调用 triggerRef 强制更新
  triggerRef(data);
</script>
triggerRef

一般配合

shallowRef

一起使用,起到提高

shallowRef

的灵活性的同时又能优化性能的效果。需要注意执行顺序确保在修改了

shallowRef

内部对象的属性之后才调用。

三、 customRef()

简述:

customRef

功能非常之强大,

customRef

可以创建自定义的

ref

对象,这些对象可以有更复杂的依赖跟踪和依赖更新逻辑。具体是

customRef

接收一个工厂函数,该函数必须要返回一个具有

get

set

方法的对象。这些方法用于读取和修改引用值,并且通过

get

set

里面的逻辑可以显式地控制依赖关系的跟踪和响应式更新。

代码示例: 实现一个有防抖功能的

ref

,第9和17行的

track()

trigger()

是固定写法,这是

vue3

底层响应式原理相关的,这里就不多解释了。

<scriptlang="ts"setup>import{ customRef }from'vue';functiondebouncedRef(initialValue, delay){let timeoutId;returncustomRef((track, trigger)=>({get(){// 使用 track 函数标记依赖track();return initialValue;},set(newValue){clearTimeout(timeoutId);
      timeoutId =setTimeout(()=>{
        initialValue = newValue;// 使用 trigger 函数触发依赖更新trigger();}, delay);}}));}// 使用自定义的refconst myDebouncedRef =debouncedRef('Hello Word',500);</script>

在上述例子中,

debouncedRef

是一个自定义的

ref

工厂函数,它接收两个参数分别是初始值和延迟时间。当

set

方法被调用时,会清除之前的计时器并设置一个新的计时器,在延迟时间结束后更新值并触发依赖更新。

在组件中使用:

<scriptlang="ts"setup>import{ onMounted }from'vue';import{ debouncedRef }from'./debouncedRef';exportdefault{setup(){const myDebouncedRef =debouncedRef('Hello Word',500);onMounted(()=>{// 在组件挂载后,可以通过 .value 访问 ref 的值
      console.log(myDebouncedRef.value);// 时间到之后返回 'Hello Word'});},};</script>

注意:

customRef

返回的对象必须有一个

value

属性用于访问或修改引用的值,这是

vue

规定的。除此以外

customRef

能根据业务需求实现各种定制化的

ref

, 如异步更新、条件性更新、防抖、节流等

四、 shallowReactive()

简述:

reactive

的浅层作用形式, 和

shallowRef

的功能比较类似。

shallowReactive

与普通的

reactive

的区别在于,

shallowReactive

不会对对象进行深度的响应式处理,也就是

shallowReactive

包含的对象内部的属性发生变化时,

shallowReactive

本身不会触发重新渲染或响应式更新,所以使用

shallowReactive

时只关心顶层的引用变化。

代码示例:

<scriptlang="ts"setup>import{ shallowReactive, isReactive }from'vue';const statetest =shallowReactive({foo:1,nested:{age:18,},});

  statetest.foo++;// 更改状态自身的属性是响应式的// 下层嵌套对象不会被转为响应式isReactive(statetest.nested);// false

  statetest.nested.age++;// 不是响应式的</script>

作为性能优化的一种手段,当业务场景中有大量复杂数据结构但只有顶层引用需要响应式时就非常有用,但你需要更加注意对象的更新逻辑,确保在需要时正确地应用响应式转换。

五、 toRaw()

简述:

toRaw

用于获取

reactive

ref

创建的响应式代理对象的原始值。当我们使用

reactive

ref

创建一个对象或值时,

Vue

会在内部创建一个代理对象,这个代理对象能够追踪属性的变化并触发视图的更新。但有时候需要访问这个对象的非响应式版本时

toRaw

就派上用场了。

代码示例:

<script lang="ts" setup>
  import { reactive, toRaw } from 'vue';

  const state = reactive({ count: 0 });

  // 获取响应式转为原始对象
  const rawState = toRaw(state);

  // 修改原始对象不会触发响应式更新
  rawState.count = 10;
  // 仍然输出 0,因为 state 是响应式代理,未被修改
  console.log(state.count); 
</script>

使用

toRaw

获取的原始对象将不再具有响应性。即

toRaw

提供了一种方式来绕过

Vue

的响应式系统,这对于性能优化和处理外部库至关重要。当正在处理一个大的数据结构,并且知道某些操作不会导致

UI

更新时使用特别合适。

六、 markRaw()

简述:作用是标记一个对象,使其不再被

reactive

shallowReactive

转换为响应式代理。即你之后试图用这些函数包装这个对象,它也会保持原样,不会变成响应式的。

代码示例:

markRaw

主要用于标记对象,而不是基本类型的值

<script lang="ts" setup>
  import { markRaw } from 'vue';

  const someObject = { name: '天天鸭' };
  const markedObject = markRaw(someObject);

  // 即使使用 reactive,markedObject 也不会变成响应式
  const state = reactive({ obj: markedObject });
</script>

注意:

markRaw

不适用于

ref

,因为

ref

的工作方式与

reactive

有点区别。

ref

主要用于创建一个响应式引用,它可以封装任何类型的值如字符串、数字和对象。当你创建一个

ref

时,

Vue

并不是将整个对象转换为响应式代理,而是将

ref

本身作为一个响应式引用,通过

value

属性来访问和修改其内部的值。

因此,当你将一个对象放入

ref

时,

ref

本身依然是响应式的,而

markRaw

的作用是阻止对象被转换为响应式,这和

ref

的设计并不匹配。

七、 shallowReadonly()

简述:

readonly

的浅层作用形式。和

readonly

类似,

shallowReadonly

会把对象的属性变为只读,但是它只会影响到对象的顶层属性,而不会递归地使对象内部的属性也变为只读。

代码示例:

<script lang="ts" setup>
import { shallowReadonly } from 'vue';

const state = {
  name: '天天鸭',
  profile: {
    age: 18,
    address: {
      city: '广州',
    }
  }
};
const shallowState = shallowReadonly(state);

// 这将会抛出错误,因为顶层属性是只读的
shallowState.name = 'change天天鸭';

// 这是可以的,因为 `profile` 对象没有被设为只读
shallowState.profile.age = 31; 

// 同样,`address` 对象也可以被修改
shallowState.profile.address.city = '深圳';
</script>

使用

shallowReadonly

的对象在顶层是只读的,但其内部的嵌套对象或数组仍然可以被修改。如果数据结构第一层业务需求不会改变就特别适用。

小结:

在真实做项目时其实不用这些进阶用法同样能实现功能,但是在合适的场景用上了却能锦上添花,作为一个有一定经验的

vue

程序员更是要必会了。如果我写的哪里不对或者不好欢迎大佬指出。


本文转载自: https://blog.csdn.net/m0_70705683/article/details/140600065
版权归原作者 贫僧法号依平 所有, 如有侵权,请联系我们删除。

“vue3响应式用法(高阶性能优化)”的评论:

还没有评论