文章目录
- 前言
- 一、首页源码+详细注释说明+技术分析
- 1. 页面功能分析
- 2. 代码+详细注释
- 二、效果展示
- 总结
前言
前三篇文章详细介绍了首页的响应式布局,采用关注点分离进行模块拆解,现在只需按需引入模块,页面更加简洁,代码的维护性得到提升。今天将进入首页的收尾阶段,即完成剩余区块列表、交易列表接口数据渲染,轮训,各种钩子使用以提升性能。
有人可能会说频繁轮询接口会不会影响性能,当然会,但是我们做了一些措施,可以有效地优化性能。首先,我们使用了useMemo和memo等性能钩子函数,就是为了避免重复渲染。同时,使用useQuery处理请求时,它提供了一些性能优化的功能,比如自动缓存和懒加载。
一、首页源码+详细注释说明+技术分析
1. 页面功能分析
(1)页面组成:页面由渲染Banner、搜索块、统计项、哈希速率图表、区块时间图表、区块列表和交易列表等模块组成
(2)数据获取:使用@tanstack/react-query库进行数据获取、缓存、轮训
(3)性能处理:使用React钩子,如useMemo、useTranslation来管理状态、获取数据和国际化,提升性能
(4)自定义钩子使用:使用自定义钩子useStatistics生成并显示统计数据
(5)详细模块封装请看前面三讲首页响应式构建之banner/搜索/统计模块布局、首页响应式构建之区块/交易布局、优化实现首页Echarts模块数据渲染
2. 代码+详细注释
// @/page/Home/index.tsx
import { FC, useMemo } from "react";
import classNames from "classnames";
import { useTranslation } from "react-i18next";
import { useQuery } from "@tanstack/react-query";
import Content from "@/components/Content";
import Banner from "./Banner";
import SearchBlock from "./SearchBlock";
import HashRateEchart from "./HashRateEchart/index";
import BlockTimeChart from "./BlockTimeChart/index";
import BlockList from "./BlockList";
import TranctionList from "./TranctionList";
import { HomeStatisticBlock, HomeStatisticItem, HomeTableBlock } from "./styled";
import { queryBlocks, queryTransactions } from "@/api/home";
import { BLOCK_POLLING_TIME } from "@/global/constants/common";
import { useStatistics } from "./requester";
const HomePage: FC = () => {
// 使用useQuery,异步获取最新的区块数据
const blocksQuery = useQuery(
["latest_blocks"],
async () => {
const { data } = await queryBlocks({
page: 1, // 从第一页开始获取
page_size: 25, // 每页获取25个区块
});
// 将获取到的区块数据转换为我们需要的格式
const blocks = data.map((wrapper: any) => {
return {
...wrapper.attributes,
};
});
return {
blocks, // 最新的区块列表
total: data?.length, // 最新区块的总数
};
},
{
refetchInterval: BLOCK_POLLING_TIME, // 每隔一段时间重新获取最新的区块数据
}
);
// 使用useMemo钩子,blocksQuery数据变化时,重新获取
const blocks = useMemo(() => blocksQuery.data?.blocks.slice(0, 10) ?? [], [blocksQuery.data?.blocks]);
// 使用useQuery,异步获取最新的交易数据
const transactionsQuery = useQuery(
["latest_transactions"],
async () => {
const { data } = await queryTransactions({
page: 1,
page_size: 25,
});
const transactions = data.map((wrapper: any) => {
return {
...wrapper.attributes,
};
});
// 将获取到的交易数据转换为我们需要的格式
return {
transactions,
total: transactions?.length,
};
},
{
refetchInterval: BLOCK_POLLING_TIME,
}
);
// 使用useMemo钩子,transactionsQuery数据变化时,重新获取
const transactions = useMemo(() => transactionsQuery.data?.transactions.slice(0, 10) ?? [], [transactionsQuery.data?.transactions]);
// 定义统计数据类型声明
interface EchartsAndData {
name: string;
value: string;
}
const useEchartsAndDataList = (): EchartsAndData[] => {
const { t } = useTranslation();
const statistics = useStatistics();
return [
{
name: t("home.echartsAndData.name1"),
value: t(statistics.value1),
},
{
name: t("home.echartsAndData.name2"),
value: t(statistics.value2),
},
{
name: t("home.echartsAndData.name3"),
value: t(statistics.value3),
},
{
name: t("home.echartsAndData.name4"),
value: t(statistics.value4),
},
];
};
// 使用区块链统计数据
const echartsAndDataList = useEchartsAndDataList();
// 统计数据渲染结构体
const StatisticItem = ({ data }: { data: EchartsAndData }) => (
<HomeStatisticItem>
<div className={classNames("statistic-item-left-title")}>{data.name}</div>
<div className={classNames("statistic-item-left-value")}>{data.value}</div>
</HomeStatisticItem>
);
return (
<Content>
{/* Banner模块 */}
<Banner />
<div className="container">
{/* 搜索模块 */}
<SearchBlock />
{/* echarts图表以及统计数据模块 */}
<HomeStatisticBlock>
<div className={classNames("statistic-item")}>
<div className={classNames("statistic-item-left")}>
{/* 统计数据 */}
<StatisticItem data={echartsAndDataList[0]}></StatisticItem>
<StatisticItem data={echartsAndDataList[1]}></StatisticItem>
</div>
<div className={classNames("statistic-item-right")}>
{/* 统计图表 */}
<HashRateEchart />
</div>
</div>
<div className={classNames("statistic-item")}>
<div className={classNames("statistic-item-left")}>
{/* 统计数据 */}
<StatisticItem data={echartsAndDataList[2]}></StatisticItem>
<StatisticItem data={echartsAndDataList[3]}></StatisticItem>
</div>
<div className={classNames("statistic-item-right")}>
{/* 统计图表 */}
<BlockTimeChart />
</div>
</div>
</HomeStatisticBlock>
</div>
<HomeTableBlock className="container">
{/* 区块列表模块 */}
<BlockList blocks={blocks} />
{/* 交易列表模块 */}
<TranctionList transactions={transactions} />
</HomeTableBlock>
</Content>
);
};
export default HomePage;
----------------------------------------------------------------------------------------------------
// @/pages/Home/styled.tsx
import styled from "styled-components";
import variables from "@/styles/variables.module.scss";
export const HomeStatisticBlock = styled.div`
width: 100%;
height: 207px;
display: flex;
margin-bottom: 20px;
.statistic-item {
display: flex;
align-items: center;
justify-content: space-between;
flex: 1;
background: #232323;
@media (max-width: ${variables.extraLargeBreakPoint}) {
flex-direction: column;
}
@media (max-width: ${variables.mobileBreakPoint}) {
}
.statistic-item-left {
flex: 1;
width: 100%;
height: 100%;
}
.statistic-item-right {
flex: 2;
width: 100%;
height: 100%;
padding: 10px;
// background: linear-gradient(304deg, #6e85e0 2%, #577cdb 48%, #486ecc 99%);
@media (max-width: ${variables.extraLargeBreakPoint}) {
}
@media (max-width: ${variables.mobileBreakPoint}) {
}
}
&:last-child {
background: #484e4e;
}
}
@media (max-width: ${variables.extraLargeBreakPoint}) {
height: 310px;
}
@media (max-width: ${variables.mobileBreakPoint}) {
flex-direction: column;
height: auto;
}
`;
export const HomeStatisticItem = styled.div`
padding: 30px;
display: flex;
justify-content: space-between;
flex-direction: column;
color: #fff;
.statistic-item-left-title {
font-size: 14px;
margin-bottom: 5px;
}
.statistic-item-left-value {
font-size: 18px;
font-weight: bold;
}
@media (max-width: ${variables.extraLargeBreakPoint}) {
padding: 15px 30px;
flex-direction: row;
margin-bottom: 0;
.statistic-item-left-value {
font-size: 16px;
}
}
@media (max-width: ${variables.mobileBreakPoint}) {
padding: 10px 20px;
}
`;
export const HomeTableBlock = styled.div`
display: flex;
@media (max-width: ${variables.extraLargeBreakPoint}) {
}
@media (max-width: ${variables.mobileBreakPoint}) {
flex-direction: column;
}
`;
二、效果展示
(1)PC端区块列表、交易列表轮询
(2)PC端搜索查询
(3)移动端区块列表、交易列表轮询
(4)移动端搜索查询
总结
关注本栏目,会实时更新。