• React+TS前台项目实战(二十九)-- 首页构建之性能优化实现首页Echarts模块数据渲染



    前言

    还记得之前我们创建的 高性能可配置Echarts组件 吗?今天我们将利用它来呈现首页统计模块的数据可视化效果,借助这个组件,我们能够显著减少编写代码的工作量,会方便很多。

    Echart模块源码+功能分析+数据渲染

    一、HashRateEchart统计图

    1. 功能分析

    (1)数据获取:使用@tanstack/react-query库来处理数据获取。使用useQuery请求并缓存数据
    (2)组件缓存:使用memo高阶组件进行缓存。有助于提高性能,防止不必要的重新渲染组件
    (3)数据处理:使用useMemo钩子缓存处理后的图表数据(fullEchartData和echartData),确保只有在必要时才进行数据处理,从而减少不必要的计算
    (4)懒加载处理:组件根据数据的可用性进行条件渲染,数据加载中时显示Loading组件
    (5)引用公共组件:使用Echart公共组件,提高开发效率,组件可看之前文章 高性能可配置Echarts图表组件封装

    2. 代码+详细注释

    // @/components/Home/HashRateEchart/index.tsx
    import { memo, useMemo } from "react";
    import BigNumber from "bignumber.js";
    import { HomeChartBlock, ChartLoadingBlock } from "./styled";
    import classNames from "classnames";
    import "echarts/lib/chart/line";
    import "echarts/lib/component/title";
    import echarts from "echarts/lib/echarts";
    import { useTranslation } from "react-i18next";
    import { useQuery } from "@tanstack/react-query";
    import Loading from "@/components/Loading";
    import { ReactChartBlock } from "@/components/Echarts/common";
    import { queryStatisticHashRate } from '@/api/home'
    // echarts 配置
    const useOption = () => {
      const { t } = useTranslation();
      return (data: any, useMiniStyle: boolean): echarts.EChartOption => {
        return {
          color: ["#ffffff"],
          title: {
            text: "平均出块时间(s)",
            textAlign: "left",
            textStyle: {
              color: "#ffffff",
              fontSize: 14,
              fontWeight: "lighter",
              fontFamily: "Lato",
            },
          },
          grid: {
            left: useMiniStyle ? "1%" : "2%",
            right: "3%",
            top: useMiniStyle ? "20%" : "15%",
            bottom: "2%",
            containLabel: true,
          },
          xAxis: [
            {
              axisLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 1,
                },
              },
              data: data.map((item: any) => item.xTime),
              axisLabel: {
                formatter: (value: string) => value,
              },
              boundaryGap: false,
            },
          ],
          yAxis: [
            {
              position: "left",
              type: "value",
              scale: true,
              axisLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 1,
                },
              },
              splitLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 0.5,
                  opacity: 0.2,
                },
              },
              axisLabel: {
                formatter: (value: string) => new BigNumber(value),
              },
              boundaryGap: ["5%", "2%"],
            },
            {
              position: "right",
              type: "value",
              axisLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 1,
                },
              },
            },
          ],
          series: [
            {
              name: t("block.hash_rate"),
              type: "line",
              yAxisIndex: 0,
              lineStyle: {
                color: "#ffffff",
                width: 1,
              },
              symbol: "none",
              data: data.map((item: any) => new BigNumber(item.yValue).toNumber()),
            },
          ],
        };
      };
    };
    // 使用memo钩子函数提升性能
    export default memo(() => {
      // 使用useQuery请求数据
      const query = useQuery(["StatisticHashRate"], async () => {
        const { data,total } = await queryStatisticHashRate({
          page: 1,
          page_size: 25,
        });
        return {
          data,
          total: total ?? data?.length,
        };
      }, {
        refetchOnWindowFocus: false,
      });
      // 处理数据,并通过useMemo实现数据的缓存
      const fullEchartData = useMemo(() => query.data ?? [], [query.data]);
      // 获取最近14天的数据,并通过useMemo实现数据的缓存
      const echartData = useMemo(() => {
        const last14Days = -15;
        return fullEchartData.slice(last14Days);
      }, [fullEchartData]);
      // 根据数据渲染图表,当数据为空时显示没有数据,正在请求数据时显示加载中
      if (query.isLoading || !echartData?.length) {
        return <ChartLoadingBlock>{query.isLoading ? <Loading size="small" /> : <div className={classNames("no-data")}>暂无数据</div>}</ChartLoadingBlock>;
      }
      // 获取echarts的option配置
      const parseOption = useOption();
      return (
        <HomeChartBlock to="/block-list">
          {/* 使用公共Echart组件 */}
          <ReactChartBlock
            option={parseOption(echartData, true)}
            notMerge
            lazyUpdate
            style={{
              height: "180px",
            }}
          ></ReactChartBlock>
        </HomeChartBlock>
      );
    });
    --------------------------------------------------------------------------
    import styled from "styled-components";
    import Link from "@/components/Link";
    export const HomeChartBlock = styled(Link)`
      canvas {
        cursor: pointer;
      }
    `;
    export const ChartLoadingBlock = styled.div`
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      .no-data {
        font-size: 18px;
      }
    `;
    

    二、BlockTimeChart统计图

    1. 功能分析

    注:此处忽略,功能和上面HashRateEchart统计表基本一致,只是数据请求不同

    2. 代码+详细注释

    // @/components/Home/BlockTimeChart/index.tsx
    import { memo, useMemo } from "react";
    import BigNumber from "bignumber.js";
    import { HomeChartBlock, ChartLoadingBlock } from "./styled";
    import classNames from "classnames";
    import "echarts/lib/chart/line";
    import "echarts/lib/component/title";
    import echarts from "echarts/lib/echarts";
    import { useTranslation } from "react-i18next";
    import { useQuery } from "@tanstack/react-query";
    import Loading from "@/components/Loading";
    import { ReactChartBlock } from "@/components/Echarts/common";
    import { queryStatisticAverageBlockTimes } from '@/api/home'
    // echarts 配置
    const useOption = () => {
      const { t } = useTranslation();
      return (data: any, useMiniStyle: boolean): echarts.EChartOption => {
        return {
          color: ["#ffffff"],
          title: {
            text: "哈希率(H/s)",
            textAlign: "left",
            textStyle: {
              color: "#ffffff",
              fontSize: 14,
              fontWeight: "lighter",
              fontFamily: "Lato",
            },
          },
          grid: {
            left: useMiniStyle ? "1%" : "2%",
            right: "3%",
            top: useMiniStyle ? "20%" : "15%",
            bottom: "2%",
            containLabel: true,
          },
          xAxis: [
            {
              axisLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 1,
                },
              },
              data: data.map((item: any) => item.xTime),
              axisLabel: {
                formatter: (value: string) => value,
              },
              boundaryGap: false,
            },
          ],
          yAxis: [
            {
              position: "left",
              type: "value",
              scale: true,
              axisLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 1,
                },
              },
              splitLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 0.5,
                  opacity: 0.2,
                },
              },
              axisLabel: {
                formatter: (value: string) => new BigNumber(value),
              },
              boundaryGap: ["5%", "2%"],
            },
            {
              position: "right",
              type: "value",
              axisLine: {
                lineStyle: {
                  color: "#ffffff",
                  width: 1,
                },
              },
            },
          ],
          series: [
            {
              name: t("block.hash_rate"),
              type: "line",
              yAxisIndex: 0,
              lineStyle: {
                color: "#ffffff",
                width: 1,
              },
              symbol: "none",
              data: data.map((item: any) => new BigNumber(item.yValue).toNumber()),
            },
          ],
        };
      };
    };
    // 使用memo钩子函数提升性能
    export default memo(() => {
      // 使用useQuery请求数据
      const query = useQuery(["StatisticAverageBlockTimes"], async () => {
        const { data,total } = await queryStatisticAverageBlockTimes({
          page: 1,
          page_size: 25,
        });
        return {
          data,
          total: total ?? data?.length,
        };
      }, {
        refetchOnWindowFocus: false,
      });
      // 处理数据,并通过useMemo实现数据的缓存
      const fullEchartData = useMemo(() => query.data ?? [], [query.data]);
      // 获取最近14天的数据,并通过useMemo实现数据的缓存
      const echartData = useMemo(() => {
        const last14Days = -15;
        return fullEchartData.slice(last14Days);
      }, [fullEchartData]);
      // 根据数据渲染图表,当数据为空时显示没有数据,正在请求数据时显示加载中
      if (query.isLoading || !echartData?.length) {
        return <ChartLoadingBlock>{query.isLoading ? <Loading size="small" /> : <div className={classNames("no-data")}>暂无数据</div>}</ChartLoadingBlock>;
      }
      // 获取echarts的option配置
      const parseOption = useOption();
      return (
        <HomeChartBlock to="/block-list">
          {/* 使用公共Echart组件 */}
          <ReactChartBlock
            option={parseOption(echartData, true)}
            notMerge
            lazyUpdate
            style={{
              height: "180px",
            }}
          ></ReactChartBlock>
        </HomeChartBlock>
      );
    });
    -------------------------------------------------------------------------------------------------------
    // @/components/Home/BlockTimeChart/styled.tsx
    import styled from "styled-components";
    import Link from "@/components/Link";
    export const HomeChartBlock = styled(Link)`
      canvas {
        cursor: pointer;
      }
    `;
    export const ChartLoadingBlock = styled.div`
      height: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      .no-data {
        font-size: 18px;
      }
    `;
    

    三、使用方式

    结合首页响应式构建之banner、搜索、统计模块布局 这一讲,在统计模块中引入出块统计图表,以及挖矿统计图表即可

    // 引入组件和echarts
    import HashRateEchart from "./HashRateEchart/index";
    import BlockTimeChart from "./BlockTimeChart/index";
    // 使用
    // ....
    <HashRateEchart />
    // ....
    <BlockTimeChart />
    // ....
    

    四. 数据渲染后效果如下

    (1)PC端

    在这里插入图片描述
    (2)移动端

    在这里插入图片描述


    总结

    下一篇讲【首页响应式构建之实现全页面数据】。关注本栏目,将实时更新。

  • 相关阅读:
    BlockCanary原理解析
    助力工业物联网,工业大数据之服务域:Shell调度测试【三十三】
    Toronto Research Chemicals霉菌毒素分析丨伏马菌素B2
    java 并发篇
    聚焦数字化项目管理——2023年PMI项目管理大会亮点回顾
    95、Spring Data Redis 之使用RedisTemplate 实现自定义查询 及 Spring Data Redis 的样本查询
    C++核心编程--继承篇
    Javascript Summery3 TOUCH SCREEN COMMON CSS
    技术停滞:如何更新?
    JavaScript 虚拟键盘:Mindfusion JavaScript Keyboard
  • 原文地址:https://blog.csdn.net/weixin_43883615/article/details/140337868