它如何呈现一个 React 列表,它依次从骨架到实际数据?

How do it render a React list where it sequentially goes from a skeleton to the actual data?

提问人:Mikkel Rank 提问时间:10/24/2023 最后编辑:Mikkel Rank 更新时间:10/24/2023 访问量:33

问:

介绍信息:我目前正在开发一个使用 TypeScript 的 React 项目。

在手头的项目中,我正在实现一个显示卡片的列表功能。在没有数据的情况下,会向用户显示骨架列表。一旦数据可用,列表就会转换以显示具有顺序效果的实际卡片,逐渐将不透明度从 0 更改为 1。

但是,我渴望实现更精致的过渡效果。具体来说,在加载状态期间,当骨架可见时,在获取数据时,我希望每个加载骨架按顺序过渡到其对应的卡片中,而不是让骨架完全消失,然后被卡片列表替换。

我所期望的过渡效果与Airbnb首页上观察到的效果非常相似。

我当前的实现类似于以下内容:

这是列表组件:

export const ListComponent = ({
  data = [],
}) => {
  const ref = useRef<HTMLDivElement>(null);
  const [responsiveHeight, setResponsiveHeight] = useState(0);

  const updateHeight = () => {
    setTimeout(() => {
      const gridItem = ref.current;
      if (gridItem) {
        const gridItemWidth = gridItem.clientWidth;
        const newHeight = (gridItemWidth * 4) / 3.5;
        setResponsiveHeight(newHeight);
      }
    }, 100);
  };

  useEffect(() => {
    updateHeight();
    window.addEventListener('resize', updateHeight);
    return () => {
      window.removeEventListener('resize', updateHeight);
    };
  }, []);

  const columns = useMemo(() => {
    if (isSm) return 1;
    if (isLg) return 2;
    return 3;
  }, [isSm, isLg]);

  if (data.length <= 0) return <ListSkeleton />;

  return (
    <Box minHeight={500}>
      <Grid container columnSpacing={3} rowGap={isSm ? 3 : 6} columns={columns}>
        {data.map((item, index) => (
          <StyledGridItem
            key={item.id}
            ref={ref}
            index={index}
            item
            xs={1}
          >
            <Card
              item={item}
              height={responsiveHeight}
            />
          </StyledGridItem>
        ))}
      </Grid>
    </Box>
  );
};

const fadeIn = keyframes`
  from { opacity: 0; }
  to { opacity: 1; }
`;

const StyledGridItem = styled(Grid)<{ index: number }>`
  opacity: 0;
  animation: ${fadeIn} 0.3s ease-in-out forwards;
  animation-delay: ${(props) => props.index * 0.075}s;
`;

这是列表项组件:

export const Card = ({
  item,
  height
}) => {
  const router = useRouter();


  return (
    <a href={`/example`} >
      <StyledCard maxHeight={Math.min(height, 464)}>
        <CardImage src={item.image} height={height} />
        <CardDetails item={item}  />
      </StyledCard>
    </a>
  );
};

const StyledCard = styled(Stack)`
  position: relative;
  width: 100%;
  border-radius: 12px;
  box-shadow: ${Theme.shadows.medium};

  :hover {
    filter: brightness(95%);
    box-shadow: ${Theme.shadows.large};
  }
`;

我曾尝试使用 React-spring 解决这个问题,但没有任何成功 - 并且认为每张卡可能都应该显示它们自己的骨架。

CSS ReactJS 打字稿 动画 下一个.js

评论


答: 暂无答案