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

使用@egjs/react-infiniteGrid的GatsbyJS画廊重渲染时样式丢失问题排查

问题分析与解决方案

看起来你遇到的问题是状态更新触发父组件重渲染时,@egjs/react-infiniteGrid 的 Masonry 布局没有自动重新计算,导致网格定位样式丢失,图片变成单列排列。当你点击"Test"按钮切换showLightbox状态时,父组件Lighting会重新渲染,子组件GalleryComp也会跟着重渲染,但MasonryInfiniteGrid没有触发布局更新逻辑,原本的网格定位样式因此失效。

核心原因

  1. 父组件状态变化触发全局重渲染,GalleryComp作为子组件被强制重新渲染,但MasonryInfiniteGrid没有感知到这次重渲染,未执行布局计算。
  2. 组件内的items、images等数据每次渲染都重新生成,没有缓存优化,加重了不必要的重渲染,也干扰了网格组件的状态感知。

具体解决方案

1. 优化组件渲染,减少不必要的重渲染

用React.memo和useMemo/useCallback来缓存组件和计算结果,避免无意义的重渲染:

// Gallery.tsx
import { memo, useMemo, useCallback } from "react";

// 用memo包裹Item组件,避免每次渲染都重新创建
const Item = memo(({ num, images }: any) => (
  <div className="item h-auto" style={{ width: "250px" }} >
    <div className="thumbnail">
      <GatsbyImage 
        image={getImage(images[num])} 
        alt="gallery image" 
        className="rounded-xl shadow-xl" 
        imgStyle={{ objectFit: "contain" }} 
      />
    </div>
  </div>
));

// 用memo包裹GalleryComp,仅在props变化时重渲染
export default memo(function GalleryComp(props: any) {
  // 用useMemo缓存images,避免每次渲染都重新映射数据
  const images = useMemo(() => {
    return props.query.allFile.edges.map(
      ({ node }) => node.childImageSharp.gatsbyImageData
    );
  }, [props.query]);

  const numPics = useMemo(() => props.query.allFile.edges.length, [props.query]);

  // 用useCallback缓存getItems函数,避免每次渲染重新创建
  const getItems = useCallback((nextGroupKey: number, count: number) => {
    const nextItems = [];
    const nextKey = nextGroupKey * count;
    for (let i = 0; i < count; ++i) {
      nextItems.push({ groupKey: nextGroupKey, key: nextKey + i });
    }
    return nextItems;
  }, []);

  const [items, setItems] = React.useState(() => getItems(0, numPics));

  const igRef = useRef();

  return (
    <>
      <MasonryInfiniteGrid 
        className="container" 
        gap={5} 
        ref={igRef} 
        onRequestAppend={(e) => {
          const nextGroupKey = (+e.groupKey! || 0) + 1;
          // 用函数式更新items,确保获取最新状态
          setItems(prevItems => [...prevItems, ...getItems(nextGroupKey, numPics)]);
        }} 
      >
        {items.map((item) => (
          <Item 
            data-grid-groupkey={item.groupKey} 
            key={item.key} 
            num={item.key} 
            images={images} 
          />
        ))}
      </MasonryInfiniteGrid>
    </>
  );
});

2. 强制触发网格布局更新

在GalleryComp中添加useEffect,监听可能影响布局的变量,主动调用网格实例的layout方法重新计算布局:

// 加入GalleryComp组件内部
useEffect(() => {
  // 当组件重渲染或items变化时,强制触发布局计算
  if (igRef.current) {
    igRef.current.layout();
  }
}, [items, numPics]);

3. 调整父组件的条件渲染逻辑

如果不需要Hello!元素和按钮同处一个容器,可以把条件渲染的元素移到画廊容器之外,减少对画廊组件渲染的干扰:

// Page.tsx
return (
  <>
    <div className="mt-64">
      <div className="flex flex-col items-center justify-center mb-10">
        <button onClick={() => setShowLightbox(true)} className="text-white border-2 border-white rounded-xl p-2">Test</button>
      </div>
      {showLightbox && <p className="text-white text-center mb-10">Hello!</p>}
      <GalleryComp query={query} />
    </div>
  </>
);

验证效果

应用以上修改后,当你点击"Test"按钮切换状态时,GalleryComp不会被不必要地重渲染;即使触发重渲染,也会主动调用网格组件的布局方法,确保网格样式保持正常。

内容的提问来源于stack exchange,提问作者Jack Pollock

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 17:44:11