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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 02:39:25