You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React/Gatsby/Chakra UI项目千条MDX列表渲染DOM过多性能优化问询

你遇到的是大量DOM节点渲染导致的性能问题,用**虚拟滚动(窗口化渲染)**就能解决,实现逻辑是仅保留视口内的条目DOM,滚动时动态替换内容,DOM数量会直接降到30以内,Lighthouse性能评分可以升到90+。

具体实现步骤

  1. 安装虚拟滚动依赖
npm install react-window
# 或者用yarn
yarn add react-window
  1. 替换原有首页代码如下:
import * as React from "react";
import { ChakraProvider, chakra, Box, HStack, Button, VStack, Wrap, WrapItem, Badge, useMediaQuery } from "@chakra-ui/react";
import { graphql, useStaticQuery } from 'gatsby';
import { FixedSizeGrid as Grid } from 'react-window';

// 抽离单独的条目组件
const ItemCard = ({ node }) => {
  return (
    <Box margin="2em" padding="1em">
      <HStack padding="0.4em" align="center" alignItems="stretch" justifyContent="space-between">
        <Button size="sm" shadow="md" colorScheme="blue"
          onClick={(e) => {
            e.preventDefault();
            window.location.href=`/objects/${node.frontmatter.field1.toLowerCase()}`;
          }}
        >Detail</Button>
        <Box align="center"/>
        <VStack alignItems="end" justifyContent="right">
          <Wrap columns={2} spacing={1} direction={"row-reverse"} isInline="true" shouldWrapChildren="true">
            <WrapItem>
              {node.frontmatter.field5 === true &&
              <Badge colorScheme="green">Field5</Badge>
              }
            </WrapItem>
            <WrapItem>
              {node.frontmatter.field6 === true &&
              <Badge colorScheme="blue">Field6</Badge>
              }
            </WrapItem>
            <WrapItem>
              {node.frontmatter.field7 === true &&
              <Badge colorScheme="orange">field7</Badge>
              }
            </WrapItem>
            <WrapItem>
              {node.frontmatter.field4 === true &&
              <Badge colorScheme="red">Field8</Badge>
              }
            </WrapItem>
          </Wrap>
        </VStack>
      </HStack>
      <Box bg="gray.300" borderRadius="0.5em" margin="0em" padding="0em">
        <chakra.h2 id={node.frontmatter.field1.toLowerCase()}>
          Field1: {node.frontmatter.field1}
        </chakra.h2>
        <chakra.p>Field2: {node.frontmatter.field2}</chakra.p>
        <chakra.p>{node.frontmatter.field3}</chakra.p>
      </Box>
    </Box>
  )
}

const IndexPage = () => {
  const query = useStaticQuery(graphql` 
  query AllObjects {
    allMdx(sort: {fields: frontmatter___field1}) {
      nodes {
        frontmatter {
          field1
          field2
          field3
          field4
          field5
          field6
          field7
          uniqueId
        }
      }
    }
  }
  `)
  const allNodes = query.allMdx.nodes
  // 响应式判断列数,和原有SimpleGrid规则一致
  const [isLg, isMd] = useMediaQuery(['(min-width: 1024px)', '(min-width: 768px)'])
  const columns = isLg ? 3 : isMd ? 2 : 1
  // 计算总行数
  const rows = Math.ceil(allNodes.length / columns)
  // 按你实际卡片高度调整,单位px
  const itemHeight = 300
  // 容器宽度默认取视口宽度,也可以自己调整
  const containerWidth = typeof window !== 'undefined' ? window.innerWidth : 1200
  const itemWidth = containerWidth / columns

  return (
    <ChakraProvider>
      <body>
          <main>
            <Grid
              columnCount={columns}
              columnWidth={itemWidth}
              height={typeof window !== 'undefined' ? window.innerHeight : 800}
              rowCount={rows}
              rowHeight={itemHeight}
              width={containerWidth}
              style={{ overflowX: 'hidden' }}
            >
              {({ columnIndex, rowIndex, style }) => {
                const index = rowIndex * columns + columnIndex
                const node = allNodes[index]
                if (!node) return null
                return (
                  <div style={style}>
                    <ItemCard node={node} />
                  </div>
                )
              }}
            </Grid>
          </main>
      </body>
    </ChakraProvider>
  )
};

export default IndexPage;

可选优化

如果你的卡片高度不固定,可以把FixedSizeGrid换成VariableSizeGrid,给不同高度的卡片设置对应行高即可;如果不想手动计算容器尺寸,可以搭配react-virtualized-auto-sizer自动适配父容器宽高。

内容的提问来源于stack exchange,提问作者Maximo.Wiki

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 03:24:05