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
相关产品推荐
相关产品推荐

