以下正文:
在 Vue 3.0 中,toRaw
、markRaw
和 customRef
是与响应式系统和引用(Refs)相关的 API。下面我将分别解释这些 API 的用途和它们如何与 Vue 3.0 的响应式系统交互。
toRaw
toRaw
是一个用于获取响应式对象原始版本的函数。在 Vue 3 中,当你使用 reactive
或 ref
创建一个响应式对象或值时,Vue 会将其包装在一个代理对象(Proxy)中,以追踪其变化并触发适当的更新。但是,在某些情况下,你可能需要访问这个响应式对象的原始版本,而不是代理对象。这就是 toRaw
的用途。
toRaw
。这通常在你希望暂时读取数据而不触发代理访问/跟踪的开销,或者写入数据而不触发更改时很有用。例如,在搜索框中,你可能绑定了一个响应式变量searchValue
,但有一个请求数据的方法不需要该变量的代理跟踪访问。这时,你可以使用toRaw
获取searchValue
的原始值,对其进行操作而不会触发数据更改时的请求方法。import { reactive, toRaw } from 'vue'
const state = reactive({ count: 0 })
const rawState = toRaw(state)
console.log(rawState === state) // false
在这个例子中,rawState
是 state
的原始版本,它与 state
不相等,因为 state
是一个代理对象。
markRaw
markRaw
是一个用于将一个对象标记为非响应式的函数。当你有一个对象,并且你知道它不需要是响应式的(例如,它来自一个第三方库或插件),但你可能仍然想将它存储在 Vue 的响应式状态中时,这可能会很有用。通过标记一个对象为非响应式,你可以避免 Vue 尝试将其转换为代理对象,从而提高性能。
markRaw
来标记它。这在一些场景中非常有用,比如当你需要集成一个第三方库或插件,并且这个库或插件的某些部分不需要是响应性的。使用markRaw
可以跳过响应式转换,从而提高性能。import { reactive, markRaw } from 'vue'
const nonReactiveObject = markRaw({ key: 'value' })
const state = reactive({
obj: nonReactiveObject
})
// state.obj 仍然是非响应式的原始对象
在这个例子中,即使 state
是响应式的,但 state.obj
仍然是非响应式的原始对象。
customRef
customRef
是一个用于创建自定义引用的函数。在 Vue 3 中,ref
用于创建一个响应式引用,但 ref
的行为是固定的:它存储一个值,并在该值变化时触发更新。然而,在某些情况下,你可能需要更复杂的逻辑来跟踪引用的变化。这就是 customRef
的用途。
customRef
接收一个工厂函数作为参数,该工厂函数返回一个具有 get
和 set
方法的对象。get
方法用于返回引用的当前值,而 set
方法用于更新引用的值并触发任何必要的副作用。
customRef
用于创建自定义的ref
,并对其依赖项跟踪和更新触发进行显式控制。这在一些需要自定义引用行为的场景中很有用,比如实现防抖函数或自定义数据验证。import { customRef } from 'vue'
function myCustomRef(value) {
let trigger = null
const setValue = (newValue) => {
if (value !== newValue) {
value = newValue
trigger()
}
}
return customRef((track, triggerValue) => {
trigger = triggerValue
return value
}, setValue)
}
const count = myCustomRef(0)
// 使用 count.value 读取和设置值,就像使用普通的 ref 一样
console.log(count.value) // 0
count.value = 1
console.log(count.value) // 1
在这个例子中,myCustomRef
创建了一个自定义引用,它允许你使用 count.value
来读取和设置值,但值的更新逻辑是自定义的。在这个简单的例子中,它只是简单地比较新旧值并在它们不同时更新值,但你可以根据需要在 setValue
函数中添加任何你想要的逻辑。
在一个复杂的Vue 3项目中,假设我们正在开发一个实时数据可视化应用,其中涉及到大量的数据处理和图形渲染。在这个场景中,我们可能会使用toRaw
、markRaw
和customRef
来优化性能和自定义响应式行为。
假设我们的应用有一个“实时数据流”组件,该组件负责接收来自服务器的实时数据,并在一个图表上进行展示。数据流的更新频率非常高,每次更新都可能导致图表的重绘。然而,由于数据处理的复杂性,我们不希望每次数据更新都立即触发图表的重新渲染,因为这可能会导致性能问题。
toRaw
读取原始数据在数据流组件中,我们可能需要处理大量的实时数据,并对其进行一些预处理。由于这些处理操作不需要触发响应式更新,我们可以使用toRaw
来获取响应式数据的原始版本,从而避免不必要的代理访问和跟踪开销。
import { reactive, toRaw } from 'vue';
// 假设我们有一个响应式的数据流状态
const dataStream = reactive({
latestData: null,
});
// 使用toRaw获取原始数据以进行预处理
const rawData = toRaw(dataStream.latestData);
// 进行一些复杂的预处理操作...
markRaw
标记非响应式数据在数据流组件中,我们可能还需要使用一些第三方库来处理数据或生成图表。这些库的数据通常不需要是响应式的,因为它们自己管理数据的更新和渲染。为了避免Vue尝试将这些数据转换为响应式对象,我们可以使用markRaw
来标记它们。
import { markRaw } from 'vue';
import { SomeChartLibrary } from 'some-chart-library';
// 假设我们有一个从服务器获取的数据对象
const serverData = fetchDataFromServer(); // 返回一个普通对象
// 使用markRaw标记该对象为非响应式
const nonReactiveData = markRaw(serverData);
// 使用第三方库生成图表
const chart = new SomeChartLibrary(nonReactiveData);
customRef
实现防抖功能在实时数据流组件中,为了避免频繁的数据更新导致图表频繁重绘,我们可以使用customRef
来实现一个防抖(debounce)功能。防抖功能可以确保在一段时间内多次触发数据更新时,只执行一次图表重绘操作。
import { customRef, ref } from 'vue';
// 自定义一个防抖ref
function debouncedRef(value, delay = 200) {
let timeout;
return customRef((track, trigger) => {
return {
get() {
track();
return value;
},
set(newValue) {
clearTimeout(timeout);
timeout = setTimeout(() => {
value = newValue;
trigger();
}, delay);
}
};
});
}
// 在数据流组件中使用防抖ref
const debouncedData = debouncedRef(null, 500); // 设置防抖延迟为500毫秒
// 当数据更新时,更新防抖ref的值
dataStream.latestData = newDataFromServer; // 假设这是从服务器获取的新数据
debouncedData.value = dataStream.latestData; // 更新防抖ref的值,但不会立即触发图表重绘
// 在图表组件中,使用debouncedData作为数据源来绘制图表
// 由于防抖功能的作用,图表只会在一段时间内数据稳定后才进行重绘
通过上述方案,我们可以利用toRaw
、markRaw
和customRef
来优化实时数据流组件的性能和响应式行为,从而提高应用的用户体验。
在Vue 3中,toRaw
、markRaw
和customRef
都是非常有用的API,它们提供了对Vue响应式系统的更细粒度的控制,以便在特定场景下优化性能或实现自定义行为。
toRaw
markRaw
customRef
ref
,可以控制其依赖项跟踪和更新触发。toRaw
和markRaw
,确保不会意外地破坏了Vue的响应式系统。customRef
提供了很大的灵活性,但也需要更加小心地管理依赖项跟踪和更新触发,以避免意外的副作用。最后
还没有使用过我们刷题网站(https://fe.ecool.fun/)或者刷题小程序的同学,如果近期准备或者正在找工作,千万不要错过,题库主打无广告和更新快哦~。
老规矩,也给我们团队的辅导服务打个广告。