从Echarts报错中学习Vue3 ref和shallowRef区别及其组件二次封装demo

 更新时间:2023年11月07日 09:01:18   作者:水冗水孚  
这篇文章主要介绍了从Echarts报错中学习Vue3 ref和shallowRef区别及其组件二次封装demo,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

报错场景

Uncaught TypeError: Cannot read properties of undefined (reading 'type') at LineView2.render (LineView.js:567:36) echarts.js:976

上述是报错信息

  • 笔者简单封装一个Echarts组件,代码文末附上,使用Vue3搭配Echarts5
  • 在初始化echarts.init图表时,没有问题,但是当进行自适应resize的时候报错了
  • 报错截图如下:

报错截图

报错原因分析

  • 报错的原因是Echarts初始化的实例变量受到了Vue响应式ref的影响——啥意思呢?就是
  • 响应式的原理就是代理,也就是说,通过ref函数加工代理的Echarts实例,已经不是原来的实例了。通俗而言,就是ref函数“克隆”了一份Echarts本体实例,本体实例自带resize方法,但是代理克隆体上的resize方法可能克隆的不太完美【这样描述不太严谨,反正是这个意思】
  • 也就可能导致了ref函数克隆体的Echarts实例在调用时出错

解决方案

  • 既然Echarts初始化的实例变量会受到Vue响应式的影响
  • 那么我们在存储Echarts的时候,就不存到Vue的响应式变量里面即可

如下:

思考,难道所有的变量,都要,都得,都必须通过ref或者reactive定义成响应式的吗?

原来的写法用ref存储:不建议

import * as echarts from "echarts";
const eChaDom = ref(null); // 用于初始化Echarts画布需要的dom元素
const chart = ref(null) // 用于存储Echarts
chart.value = echarts.init(eChaDom.value) // 初始化实例

解决方案一:直接使用普通变量来存储Echarts实例

import * as echarts from "echarts";
let eChaDom = document.querySelector('.eChaDom'); // 用于初始化Echarts画布需要的dom元素
let chart = null // 用于存储Echarts
chart = echarts.init(eChaDom) // 初始化实例

解决方案二:使用浅层响应式shallowRef进行存储Echarts实例

  • 我们知道ref响应式有些过头了,稍微一变都能感应到,而Echart的实例是不可变的
  • 你变我不变,就容易打架出问题
  • 所以,若是不想使用普通变量来存储Echarts实例,使用shallowRef进行定义存储也是可以的
  • 如下:
import * as echarts from "echarts";
const eChaDom = shallowRef(null); // 用于初始化Echarts画布需要的dom元素
const chart = shallowRef(null) // 用于存储Echarts
chart.value = echarts.init(eChaDom.value) // 初始化实例

解决方案三:依旧用ref但是搭配markRaw强制返回自身,不让代理克隆一份

import { ref, markRaw, shallowRef } from "vue";
import * as echarts from "echarts";
const eChaDom = ref(null); // 用于初始化Echarts画布需要的dom元素
const chart = ref(null) // 用于存储Echarts
chart.value = markRaw(echarts.init(eChaDom.value)) // 初始化实例
  • 这种方式有些多此一举了,本来ref就是要代理克隆的一份,我们再使用markRaw去强制不允许代理克隆一份
  • 这种方式不太推荐
  • 属于奇葩的操作

思考ref和shallowRef应用场景————性能优化

  • 我们平常定义一个变量,可以将其定义成响应式的,或者非响应式的
  • 定义成响应式的是为了后续改它,自动触发页面视图更新
  • 可是啊,在Echarts中,初始化的实例一般也不用去更改,更多的是去调用其自带的方法
  • 所以我们没必要还用ref将其定义响应式存储
  • 直接定义一个非响应式数据去存储一下也没问题的
  • 当然,折中一下,就是用浅层响应式的shallowRef来定义存储吧

实际上,这也是性能优化提升的一种方式

因为ref是把一个变量递归深层次加工成响应式【耗时不少】,而shallowRef操作加工【耗时少】

我们看官方的shallowRef和markRaw这两张图,就能够理解明白了:

图:

图:

官方地址在这

小结

  • 响应式变量有对应的好处、非响应式变量也有其优点
  • 我们应该根据实际情况,去灵活定义一个变量到底是响应式还是非响应式的【亦或是浅层响应式的】
  • 本文就是一个实际情况【shallowRef折中定义一个浅层响应式的Echarts实例的变量】
  • 时间允许下,可以多研究研究一些报错的具体原因,这样可以加深我们对于技术的理解

当然,github就这个问题,也有对应的issue。地址在这里

一句话总结,某些大一些的、不需要更改的实例化的数据对象,就不需使用ref定义成深层响应式啦(直接用普通变量存储也无妨)。若是依旧想定义成响应式的,那就使用shallowRef即可

  • 一句话总结,某些大一些的、不需要更改的实例化的数据对象,就不需使用ref定义成深层响应式啦
  • 直接用普通变量存储也无妨
  • 若是依旧想定义成响应式的,那就使用shallowRef即可

嗯,这样记,通俗易懂

封装的Echarts组件,可复现对应报错bug

组件二次封装Echarts代码

<template>
    <div ref="eChaDom" :style="{ height: h }" />
</template>
<script setup>
import { watch, onMounted, onBeforeUnmount, ref, shallowRef } from "vue";
import * as echarts from "echarts";
import debounce from 'lodash/debounce'
const props = defineProps({
    h: {
        type: String,
        default: '360px'
    },
    options: {
        type: Object,
        default: () => ({})
    },
    theme: {
        type: String,
        default: 'dark'
    }
})
// const eChaDom = ref(null); // 这样resize有报错
// const chart = ref(null)
const eChaDom = shallowRef(null); // 这样resize就没报错了
const chart = shallowRef(null)
const init = () => {
    chart.value = echarts.init(eChaDom.value, props.theme)
    chart.value.setOption(props.options);
    window.addEventListener('resize', debounce(resizeFn, 360))
}
const resizeFn = () => {
    chart.value.resize()
}
onMounted(() => {
    init()
})
watch(
    () => props.options,
    (newOptions) => {
        chart.value.setOption(newOptions);
    },
    { deep: true }
)
onBeforeUnmount(() => {
    window.removeEventListener('resize', resizeFn)
})
</script>

使用组件

<template>
    <div class="tenBox">
        <eCha :options="options" h="600px" />
    </div>
</template>
<script setup>
import eCha from "@/components/eCha/index.vue";
const options = {
    xAxis: {
        type: 'category',
        data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    },
    yAxis: {
        type: 'value'
    },
    series: [
        {
            data: [820, 932, 901, 934, 1290, 1330, 1320],
            type: 'line',
            smooth: true
        }
    ]
}

以上就是从Echarts报错中学习Vue3 ref和shallowRef区别及其组件二次封装demo的详细内容,更多关于Vue3 ref shallowRef区别的资料请关注脚本之家其它相关文章!

相关文章

  • Vue CompositionAPI中watch和watchEffect的区别详解

    Vue CompositionAPI中watch和watchEffect的区别详解

    这篇文章主要为大家详细介绍了Vue CompositionAPI中watch和watchEffect的区别,文中的示例代码简洁易懂,希望对大家学习Vue有一定的帮助
    2023-06-06
  • vue3基础知识剖析

    vue3基础知识剖析

    笔者这篇文章会从vue3基础的知识点开始剖析,特别是在将composition API的时候,在代码示例中不会一上来就使用setup语法糖,而是用早期的setup函数,这样方便于初学的小伙伴们理解跟学习
    2022-08-08
  • 解读Vue组件注册方式

    解读Vue组件注册方式

    无论是Vue还是React,都有组件的概念。组件,就是能和别人组合在一起的物件。在前端页面开发过程中,将一个页面划分成一个个小的模块,每个模块单独定义,每个模块就是一个组件。组件可以进行复用,A页面和B页面有一个相似的模块,可以抽离成一个可局部修改的组件。
    2021-05-05
  • 解决vue3.0运行项目warning Insert `·` prettier/prettier问题

    解决vue3.0运行项目warning Insert `·` prettier/pret

    这篇文章主要介绍了解决vue3.0运行项目warning Insert `·` prettier/prettier问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-10-10
  • Vue SPA 首屏优化方案

    Vue SPA 首屏优化方案

    这篇文章主要介绍了Vue SPA 首屏优化方案的的相关资料,帮助大家更好的理解和学习使用vue,感兴趣的朋友可以了解下
    2021-02-02
  • Vue路由传参及props解耦深入分析

    Vue路由传参及props解耦深入分析

    vue路由传参的使用场景一般都是应用在父路由跳转到子路由时,携带参数跳转,下面这篇文章主要给大家介绍了关于vue路由传参方式的方式总结及获取参数的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • element 穿梭框性能优化的实现

    element 穿梭框性能优化的实现

    本文主要介绍了element 穿梭框性能优化,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-10-10
  • Vue.js开发环境快速搭建教程

    Vue.js开发环境快速搭建教程

    这篇文章主要为大家详细介绍了Vue.js开发环境快速搭建教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • 深入理解Vue3组合式API的实现

    深入理解Vue3组合式API的实现

    组合式API为Vue3带来了更好的逻辑组织和复用性,支持TypeScript,提供灵活的响应式系统,它允许开发者将相关逻辑组合在一起,通过composable函数实现逻辑复用,摆脱了mixin的缺点,同时,组合式API与TypeScript的集成更紧密,能够提供更准确的类型推断
    2024-10-10
  • 详解在vue使用weixin-js-sdk常见使用方法

    详解在vue使用weixin-js-sdk常见使用方法

    这篇文章主要介绍了 详解在vue使用weixin-js-sdk常见使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-05-05

最新评论