Intersection Observer API 进入无限渲染循环

Soh*_*pta 5 typescript reactjs react-intersection-observer chakra-ui

我尝试使用交集观察器 API 在用户开始滚动时有条件地显示 CSS 网格中的项目,但它似乎进入了无限渲染循环。这是我的代码。

这是我在 StackBlitz 上的实时代码的链接

另外,我想要实现的目标是,当我可以避免时,不要在屏幕上渲染太多项目。我不确定是否display: none真的会减少浏览器的工作量。如果这不是正确的方法,请告诉我。

感谢您阅读我的问题。非常感谢任何帮助。

Lin*_*ste 2

问题:1000 个元素具有相同的引用

您有 1000 个GridItem组件,它们都获得相同的回调 ref setRefsinView尽管我们知道在任何给定时间有些人在视野中而另一些不在视野中,但它们都具有相同的价值。最终发生的情况是,每个项目都会覆盖之前设置的引用,以便所有 1000 个项目都会收到一个布尔值inView,该布尔值表示列表中的最后一个项目是否在视图中,而不是它本身是否在视图中。

解决方案:useInView对于每个元素

为了知道每个单独的组件是否在视图中,我们需要useInView对列表中的每个元素分别使用钩子。我们可以将每个项目的代码移至其自己的组件中。我们需要传递这个组件的编号ix和钩子的选项useInView(我们也可以传递根引用并options在此处创建对象)。

import { Box, Flex, Text, useColorModeValue as mode, Divider, Grid, GridItem, Center } from '@chakra-ui/react';
import { useInView, IntersectionOptions } from 'react-intersection-observer';
import React, { useRef } from 'react';

interface ItemProps {
  ix: number;
  inViewOptions: IntersectionOptions;
}

export const ListItem = ({ix, inViewOptions}: ItemProps) => {
  const {ref, inView}= useInView(inViewOptions);

  return (
    <GridItem bg={inView?"red.100":"blue.100"} ref={ref} _last={{ mb: 4 }} key={ix}>
      <Center  border={1} borderColor="gray.100" borderStyle="solid" h={16} w="100%">
        Item {ix}
      </Center>
    </GridItem>
  )
}


export type PortfolioListProps = {
  title: string;
};

export const PortfolioList = ({ 
  title,
}: PortfolioListProps) => {
  const parRef = useRef(null);

  return (
    <Box
      w="100%"
      mx="auto"
      rounded={{ md: `lg` }}
      bg={mode(`white`, `gray.700`)}
      shadow="md"
      overflow="hidden"
    >
      <Flex align="center" justify="space-between" px="6" py="4">
        <Text as="h3" fontWeight="bold" fontSize="xl">
          {title}
        </Text>
      </Flex>
      <Divider />
      <Grid
        p={4}
        gap={4}
        templateColumns="1fr 1fr 1fr 1fr"
        templateRows="min-content"
        maxH="500px"
        minH="500px"
        overflowY="auto"
        id="list"
        ref={parRef}
      >
        {[...Array(1000)].map((pt,ix) => (
          <ListItem ix={ix} key={ix} inViewOptions={{
            threshold: 1,
            rootMargin: '0px',
            root: parRef?.current,
          }}/>
        ))}
      </Grid>
    </Box>
  );
};
Run Code Online (Sandbox Code Playgroud)

StackBlitz 链接