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

Next.js 14切换语言时触发removeChild空值读取TypeError

问题根源

这个错误是因为语言切换触发组件重新渲染时,lightgallery的旧实例仍在尝试操作已被React卸载的DOM节点,导致removeChild调用时找不到目标元素。

修复方案

1. 给LightGallery绑定语言相关的唯一Key

让React在语言切换时完全卸载旧的LightGallery组件并创建新实例,避免旧实例残留操作DOM:

<LightGallery key={langCode} speed={500} plugins={[lgThumbnail, lgZoom]}>
  {/* 子元素内容 */}
</LightGallery>

2. 手动管理lightgallery实例生命周期

用useRef保存实例,在语言切换或组件卸载时主动销毁实例,防止内存泄漏和DOM操作错误:

"use client";
import { useState, useEffect, useRef } from "react";
import LightGallery from "lightgallery/react";
import lgThumbnail from "lightgallery/plugins/thumbnail";
import lgZoom from "lightgallery/plugins/zoom";
import "lightgallery/css/lg-thumbnail.css";
import "lightgallery/css/lightgallery.css";
import "lightgallery/css/lg-zoom.css";

// 其他导入保持不变

const Gallery: React.FC<IProps> = ({ langCode }) => {
  const galleryRef = useRef<any>(null);
  const [skip, setSkip] = useState(0);
  const [take, setTake] = useState(20);
  const [page, setPage] = useState<number>(0);
  const rowsPerPage = take;

  const searchParams = useSearchParams();
  const pageParams = searchParams.get("page");
  const numPage = Number(pageParams);

  useEffect(() => {
    if (numPage > 0) {
      setPage(numPage - 1);
      setSkip((numPage - 1) * rowsPerPage);
    }
  }, [numPage, rowsPerPage]);

  // 语言切换或组件卸载时销毁旧实例
  useEffect(() => {
    return () => {
      if (galleryRef.current) {
        galleryRef.current.closeGallery();
        galleryRef.current.destroy();
      }
    };
  }, [langCode]);

  // 缓存Key加入langCode,避免跨语言缓存冲突;接口如果需要语言参数也要传入
  const { data, isLoading, isError } = useClientData<IGallery>(
    `MediaGallery_${langCode}`,
    EndpointUrls.MEDIA_GALLERY(skip, take, langCode) // 根据实际接口调整参数
  );

  if (isLoading) return <Spinner />;
  if (isError) return <Error />;

  return (
    <Container className="pt-12 pb-20">
      <div className="pb-8">
        {data?.datas ? (
          <LightGallery 
            ref={galleryRef}
            key={langCode}
            speed={500} 
            plugins={[lgThumbnail, lgZoom]}
          >
            {data.datas.map((image, index) => (
              // 尽量用图片唯一ID作为key,不要用index
              <a key={image.id || index} href={`${IMAGE_URL}${image?.imagePath}`}>
                <div className="relative overflow-hidden group w-full h-[218px]">
                  <Image
                    src={`${IMAGE_URL}${image?.imagePath}`}
                    alt="Large Image"
                    width={608}
                    height={377}
                    className="w-full h-full object-cover transition-all duration-1000"
                  />
                  <p className="absolute left-[10px] bottom-[10px] font-medium text-sm text-white z-10">
                    {image?.createdDate &&
                      formatDate(image.createdDate, langCode)}
                  </p>
                  <div className="absolute inset-0 bg-none group-hover:bg-custom-gradient transition-all duration-1000"></div>
                </div>
              </a>
            ))}
          </LightGallery>
        ) : (
          <p>No images available</p>
        )}
      </div>
      <PaginationCustom
        setPage={setPage}
        page={page}
        total={data?.totalCount || 0}
        rowsPerPage={rowsPerPage}
      />
    </Container>
  );
};

export default Gallery;

3. 额外优化建议

  • 不要用index作为列表项的key,优先使用图片的唯一标识(比如image.id),提升React渲染稳定性。
  • 检查EndpointUrls.MEDIA_GALLERY接口是否需要传入langCode参数,如果返回数据和语言相关,必须添加该参数,否则切换语言后数据不会更新,也可能引发组件状态异常。

内容的提问来源于stack exchange,提问作者Ishaq Yaqublu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 07:44:53