我有一个使用React,Gatsby和Chakra UI框架的简单web应用程序。这个应用程序由一个索引页组成,它从1000+ mdx文件中查询头条,并呈现一个最小的摘要组件,其中有5个来自头条的字段和一个指向每个字段的详细页面的链接。1000+详细页面是使用createPage在gatsby-node.js中生成的。
索引页面使用map遍历每个mdx节点,并使用Chakra UI简单网格以及每个项目的其他Chakra组件。
将应用程序部署到Gatsby Cloud时收到的灯塔报告将应用程序的性能评分为60/100,这主要是由于DOM中的元素过多(由索引页面呈现的1000+摘要元素)。
我已经查看了所有相关的文档,并在其他来源中进行了搜索,但是没有找到可行的解决方案,可以只呈现在屏幕上显示的大约25个项目的html,并根据需要呈现其余的项目,而不是从一开始就呈现所有的1000+。
import * as React from "react";
import { ChakraProvider, chakra, Box, SimpleGrid, HStack, Button, VStack, Wrap, WrapItem, Badge } from "@chakra-ui/react";
import { graphql, useStaticQuery } from 'gatsby';
const IndexPage = () => {
const query = useStaticQuery(graphql`
query AllObjects {
allMdx(sort: {fields: frontmatter___field1}) {
nodes {
frontmatter {
field1
field2
field3
field4
field5
field6
field7
uniqueId
}
}
}
}
`)
return (
<ChakraProvider>
<body>
<main>
<SimpleGrid columns={{base: 1, lg: 3, md: 2, sm:1}} spacing={{base: '1.5em', lg: '1.5em', md:'1.0', sm:'0.90em'}}>
{ query.allMdx.nodes.map((node) => (
<Box key={node.frontmatter.field1} 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>
))}
</SimpleGrid>
</main>
</body>
</ChakraProvider>
)
};
export default IndexPage;发布于 2021-10-05 13:18:59
好了,你找到了解决方案。使用无限滚动或一些类似的延迟(按钮等)方法来按需呈现全部网格项目,而不是同时呈现所有网格项目。
只需创建一个包含元素切片数量的状态(useState),并在用户滚动页面时立即升级它们。这将保存(并延迟)初始的DOM元素。
我将添加一个基于按钮的方法来渲染更多的元素,但是使用无限滚动的想法是完全相同的。
const IndexPage = () => {
const query = useStaticQuery(graphql`
query AllObjects {
allMdx(sort: {fields: frontmatter___field1}) {
nodes {
frontmatter {
field1
field2
field3
field4
field5
field6
field7
uniqueId
}
}
}
}
`)
// Array of all news articles
const allGridElements = query.allMdx.nodes
// State for the list
const [list, setList] = useState([...allGridElements.slice(0, 10)])
// State to trigger the load more
const [loadMore, setLoadMore] = useState(false)
// State of whether there is more to load
const [hasMore, setHasMore] = useState(allGridElements.length > 10)
// Load more button click
const handleLoadMore = () => {
setLoadMore(true)
}
// Handle loading more articles
useEffect(() => {
if (loadMore && hasMore) {
const currentLength = list.length
const isMore = currentLength < allGridElements.length
const nextResults = isMore
? allGridElements.slice(currentLength, currentLength + 10)
: []
setList([...list, ...nextResults])
setLoadMore(false)
}
}, [loadMore, hasMore]) //eslint-disable-line
//Check if there is more
useEffect(() => {
const isMore = list.length < allGridElements.length
setHasMore(isMore)
}, [list]) //eslint-disable-line
return (
<div>
<h1>Load more demo</h1>
<div>
{list.map((item) => (
{ /* Your JSX rendering the grid items */ }
))}
</div>
{hasMore ? (
<button onClick={handleLoadMore}>Load More</button>
) : (
<p>No more results</p>
)}
</div>
)
}
export default IndexPage注意:为了避免无休止的回答,我省略了您的循环返回的JSX。只要把它放在评论里就行了。
这是不言而喻的,您将所有元素设置为React状态(useState)并遍历它。useEffect负责根据监听器更新列表。
其他有用的资源:
https://stackoverflow.com/questions/69448329
复制相似问题