toRaw 与 markRaw
目的是不想使用响应式对象
-
toRaw
,将一个响应式对象转为普通对象,对这个普通对象的操作不会引起页面更新,提高性能。 -
markRaw
,标记一个对象,使其永远不会再成为响应式对象- 有些值不应被设置为响应式的,例如复杂的第三方类库等
- 当渲染具有静态数据源的大列表时,跳过响应式转换可以提高性能
示例一
动态组件<component> is
在接收一个组件时,明确要求不能是一个响应式对象
import { ref, markRaw } from 'vue'
import Foo from './foo/index.vue'
const list = ref([
{
// ...
component: markRaw(Foo)
}
])
<template>
<div v-for="(item, index) in list" :key="index">
<component :is="item.component"></component>
<div>
</template>
示例二
Vue3 封装 echarts 时,监听窗口大小变化时,调用 echarts resize()
函数更新图表,会发现报错:
TypeError: Cannot read properties of undefined (reading 'type')
原因是,vue3默认把 echarts 实例转为响应式proxy
代理,致使 resize()
无法获取 coordSys.type
解决方案
import { ref, markRaw, onMounted } from 'vue'
import * as echarts from 'echarts'
import { EChartsOption, EChartsType } from 'echarts'
const chartRef = ref<EChartsType>()
onMounted(() => {
chartRef.value = markRaw(echarts.init(document.getElementById("chart")))
})
shallowRef
reactive
底层其实就是通过 ref
创建的;
默认情况下,无论是 ref
还是 reactive
都是深度监听;而 shallowRef / shallReactive
都是非深度监听,只会包装第一层的数据,如果想更改多层的数据,必须先更改第一层的数据,然后在去更改其他层的数据,这样视图上的数据才会发生变化。
所以,当我们试图将一个component
组件 变成响应式时,vue3会发出警告:should be avoided by marking the component with markRaw or using shallowRef instead of ref
-- 用 markRaw / shallowRef
标记组件
defineProps、defineEmits、defineExpose
defineProps
声明组件 props
传值
<script setup lang="ts">
// 采用 ts专有声明,无默认值
defineProps<{
msg: string,
num?: number
}>()
// 采用ts专有声明,有默认值
interface Props {
msg?: string
labels?: string[]
}
const props = withDefaults(defineProps<Props>(), {
msg: 'hello',
labels: () => ['one', 'two']
})
// 非ts专有声明
defineProps({
msg: String,
num: {
type:Number,
default: ''
}
})
</script>
defineEmits
子组件声明暴露的事件
<script setup lang="ts">
/*ts专有*/
const emit= defineEmits<{
(e: 'click', num: number): void
}>()
/*非ts专有*/
const emit= defineEmits(['click'])
const clickThis = () => {
emit('click', 2)
}
</script>
defineExpose
子组件暴露出去、让父组件访问的属性
// helloword.vue
import { ref, defineExpose } from 'vue'
const count = ref(123)
defineExpose({
count
})
// Something.vue
<template>
<helloword ref="hello"></helloword>
<button @click="helloClick">touch me</button>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import helloword from './components/HelloWorld.vue'
const hello = ref(null)
const helloClick = () => {
console.log(hello.value.count) // 123
}