Gatsby站点SimpleLightbox需刷新才加载的问题求助
Gatsby中SimpleLightbox路由跳转后失效的问题解决
问题重现
从「inspirations」页面进入单个灵感详情页时,点击图库图片只会直接打开图片URL,无法触发SimpleLightbox;刷新该详情页后,点击图片可正常唤起Lightbox。相关组件代码如下:
import React from 'react' import styled from 'styled-components' import { GatsbyImage } from 'gatsby-plugin-image' import SimpleLightbox from 'simple-lightbox' import 'simple-lightbox/dist/simpleLightbox.min.css' import Seo from "../components/seo" import CTAOne from '../components/ctaOne' const HeroSection = styled.section` height: 650px; position: relative; @media(min-width: 768px) { height: 825px; } .hero-image .gatsby-image-wrapper { width: 100%; height: 650px; object-fit: cover; object-position: center; @media(min-width: 768px) { height: 825px; } } .hero-content { position: absolute; bottom: 40px; left: 50%; transform: translateX(-50%); z-index: 1; text-align: center; width: calc(100% - 20px); max-width: 1160px; padding: 15px 0; background-color: var(--white-trans); .hero-border-top, .hero-border-bottom { height: 18px; width: 100%; border: 6px solid var(--white-trans); } .hero-border-top { margin-top: -33px; } .hero-border-bottom { margin-bottom: -33px; } h1 { margin-bottom: 0; } p { font-size: 21px; line-height: 1.2; width: 100%; max-width: 900px; margin: 25px auto 21px auto; padding-left: 10px; padding-right: 10px; @media(min-width: 768px) { font-size: 23px; } } } ` const InspirationPostContainer = styled.section` margin-bottom: 90px; .inspiration-desc { max-width: 850px; margin: 90px auto 85px auto; text-align: center; } .inspiration-grid { column-count: 1; column-gap: 55px; @media(min-width: 640px) { column-count: 2; } @media(min-width: 992px) { column-count: 3; } } .item { margin: 0 0 40px; display: grid; grid-template-rows: 1fr auto; break-inside: avoid; } .item > img { grid-row: 1 / -1; grid-column: 1; } ` function InspirationPost({ pageContext }) { const { inspiration } = pageContext if (typeof window !== `undefined`) { new SimpleLightbox({elements: '.inspiration-grid a'}) } return ( <> <HeroSection> <div className='hero-image'> <GatsbyImage image={inspiration.inspiration.projectFeaturedPhoto.gatsbyImage} alt={inspiration.inspiration.projectFeaturedPhoto.altText} /> </div> <div className="hero-content"> <div className='hero-border-top'></div> <h1>{inspiration.inspiration.projectTitle}</h1> <div className='hero-border-bottom'></div> </div> </HeroSection> <InspirationPostContainer> <div className="container"> <div className='inspiration-desc'>{inspiration.inspiration.projectDescription}</div> <h2>Project Gallery</h2> <div className='inspiration-grid'> {inspiration.inspiration.projectGallery.map((node) => ( <a href={`${node.mediaItemUrl}`} className='item' key={node.id}> <GatsbyImage image={node.gatsbyImage} alt={node.altText} /> </a> ))} </div> </div> </InspirationPostContainer> <CTAOne /> </> ) } export default InspirationPost
问题原因
Gatsby采用客户端路由机制,从列表页跳转到详情页时,页面不会完全刷新,组件初始化阶段执行new SimpleLightbox时,.inspiration-grid a这些DOM元素还未完成渲染,导致Lightbox无法正确绑定点击事件。而刷新页面时是完整的初始加载流程,DOM已经就绪,所以初始化成功。此外,当前代码未处理组件卸载时的实例清理,可能引发内存泄漏。
解决方案
使用React的useEffect钩子,确保在DOM渲染完成后初始化SimpleLightbox,并在组件卸载时销毁实例:
import React, { useEffect, useRef } from 'react' // ... 其他导入保持不变 function InspirationPost({ pageContext }) { const { inspiration } = pageContext const lightboxRef = useRef(null) useEffect(() => { // 确保在浏览器环境下执行 if (typeof window !== 'undefined') { // 初始化Lightbox lightboxRef.current = new SimpleLightbox({ elements: '.inspiration-grid a' }) } // 组件卸载时清理实例 return () => { if (lightboxRef.current) { lightboxRef.current.destroy() lightboxRef.current = null } } }, []) // 空依赖数组确保只在组件挂载时执行一次 return ( // ... JSX部分保持不变 ) } export default InspirationPost
关键说明
useEffect的空依赖数组保证初始化逻辑仅在组件挂载后执行一次,且此时DOM已渲染完成,能正确找到目标元素。- 使用
useRef存储Lightbox实例,方便在组件卸载时调用destroy()方法清理资源,避免内存泄漏。 - 保留
typeof window !== 'undefined'的判断,防止Gatsby服务端渲染时出现错误。
内容的提问来源于stack exchange,提问作者ccrider
相关产品推荐
相关产品推荐

