Joji
Joji

Reputation: 5615

React w Gatsby: implemented sequential fade-in animation for gallery but it doesn't work right after being deployed

The source code is here: https://codesandbox.io/s/gatsby-starter-default-nvhl7

And the deployed site is here: https://csb-nvhl7-24q4bchuz.now.sh/

The effect I am trying to achieve is simple and straightforward.

First I used this query to load all the image files from the images folder

const data = useStaticQuery(graphql`
    query {
      allFile(
        filter: {
          extension: { regex: "/(jpg)|(jpeg)|(png)/" }
          sourceInstanceName: { eq: "images" }
        }
      ) {
        edges {
          node {
            childImageSharp {
              fluid(maxWidth: 800, quality: 95) {
                aspectRatio
                src
                srcSet
                originalName
                srcWebp
                srcSetWebp
                sizes
              }
            }
          }
        }
      }
    }

Then I have a gallery component to display them by dividing these images into three groups, and we can use project1, project2 and project3 to navigate between them.

const Gallery = ({ minWidth }) => {
  let refs = {}

  const allPics = Image().map(({ childImageSharp }, i) => {
    // eslint-disable-next-line react-hooks/rules-of-hooks
    refs[i] = useRef(null)
    childImageSharp.index = i
    return childImageSharp
  })

  const firsload = allPics.slice(0, 5)
  const secload = allPics.slice(5, 10)
  const third = allPics.slice(10)

  const [imgs, setImgs] = useState(firsload)

  const thumbnails = imgs.map(img => img.fluid.srcSet.split(" ")[0])

  return (
    <>
      <ProjectsContainer>
        <Project
          onClick={() => {
            setImgs(firsload)
          }}
        >
          Project 1.
        </Project>
        <Project
          onClick={() => {
            setImgs(secload)
          }}
        >
          Project 2.
        </Project>
        <Project
          onClick={() => {
            setImgs(third)
          }}
        >
          Project 3.
        </Project>
      </ProjectsContainer>
      <Mansory gap={"0em"} minWidth={minWidth}>
        {imgs.map((img, i) => {
          return (
            <PicContainer key={img.index}>
              <Enlarger
                src={thumbnails[i]}
                enlargedSrc={img.fluid.src}
                index={img.index}
                orderIndex={i}
                onLoad={() => {
                  refs[img.index].current.toggleOpacity(1) <-- use ref to keep track of every Enlarger 
                }}
                ref={refs[img.index]}
              />
            </PicContainer>
          )
        })}
      </Mansory>
    </>
  )
}

For every Enlarger that gets rendered by the Gallery, they are a zoom image component

import Img from "react-image-enlarger"

class Enlarger extends React.Component {
  state = { zoomed: false, opacity: 0 } <--- initially every image's opacity is 0, then it shows up by being toggled opacity 1

  toggleOpacity = o => {
    this.setState({ opacity: o })
  }

  render() {
    const { index, orderIndex, src, enlargedSrc, onLoad } = this.props
    return (
      <div style={{ margin: "0.25rem" }} onLoad={onLoad}> <-- where we toggle the opacity when the element is onloaded
        <Img
          style={{
            opacity: this.state.opacity,
            transition: "opacity 0.5s cubic-bezier(0.25,0.46,0.45,0.94)",
            transitionDelay: `${orderIndex * 0.07}s`,
          }}
          zoomed={this.state.zoomed}
          src={src}
          enlargedSrc={enlargedSrc}
          onClick={() => {
            this.setState({ zoomed: true })
          }}
          onRequestClose={() => {
            this.setState({ zoomed: false })
          }}
        />
      </div>
    )
  }
}

And I have made it clear in the code snippet where I implemented the sequential fade-in animation by using ref to control every Enlarger's toggleOpacity method.

This code works great on localhost, i.e. during development. You can try the codesandbox link above to see it. However the bug appears only when the page is deployed.. Click on the deployed version (https://csb-nvhl7-24q4bchuz.now.sh/) you can see that when browser first loading the page, some pictures are missing, because their opacity are still 0, which I suspect is because refs[img.index].current.toggleOpacity(1) somehow didn't get called on the image when they are onloaded. However the weird thing is, when you navigate between the projects, there's no problems at all with this animation and opacity change, they are normal. And when you refresh the page, the problem shows up again.

I been struggling with this problem for days and couldn't figure out why. Also although here I used ZEIT Now to deploy the site, the problem didn't go away when I used Netlify to deploy.

Upvotes: 4

Views: 882

Answers (2)

Mike
Mike

Reputation: 106

In addition to Kishore's answer, you may want make your query after the page loaded (maybe in componentDidMount) and use setState to trigger react to re-render once that content has been fully loaded.

Upvotes: 0

kishore kingmaker
kishore kingmaker

Reputation: 476

Its not because of deployment, in Production Your images taking more time to load. See the image network call in the browser

Upvotes: 2

Related Questions