Jump to content
Search Community

Gsap + React/Gatsby

Fadanabela test
Moderator Tag

Warning: Please note

This thread was started before GSAP 3 was released. Some information, especially the syntax, may be out of date for GSAP 3. Please see the GSAP 3 migration guide and release notes for more information about how to update the code to GSAP 3's syntax. 

Recommended Posts

Hi!!

 

I am building my new website with Gatsby and I really wanted to make some animations with Gsap. I have been trying for days to make this work and retrieve the data from GraphQL. I searched everywhere, but I couldn't find a similar case. I am new to React and Gsap, so I am totally stuck.

 

This is a gallery component and I am trying to make the .staggerTo() transition on load. I didn't make a pen because of GraphQL things.

 

I hope it is not asking too much, but any help would be really appreciated! Thanks and best wishes!!

 

import React from 'react'
import { Link, graphql, StaticQuery } from 'gatsby'
import Img from 'gatsby-image'



export const Gallery = ({ data }) => (
    
        <Wrapper>
        <Title>
            Works
        </Title>
            <Inner>
            {data.allMarkdownRemark.edges.map(({ node }) => (
                <div key={node.id}>
                    <StyledLink to={node.fields.slug}>
                        <StyledImg fluid={node.frontmatter.image.childImageSharp.fluid} />
                        <PostTitle>
                        {node.frontmatter.title}{" "}
                        </PostTitle>
                    </StyledLink> 
                    <Date>
                        {node.frontmatter.date}
                    </Date>
                    <p>{node.excerpt}</p>
                </div>
            ))}
            </Inner>
        </Wrapper>
)

  export default props => (
    <StaticQuery
    query={graphql`
      query {
          allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
              totalCount
              edges {
              node {
                  id
                  frontmatter {
                  title
                  date(formatString: "DD MMMM, YYYY")
                  image {
                  childImageSharp {
                      fluid(maxWidth: 800) {
                      ...GatsbyImageSharpFluid_noBase64
                      }
                  }
              }
                  }
                  fields {
                  slug
                  }
                  excerpt
              }
              }
          }
          }
    `}
    render={data => <Gallery data={data} {...props} />}
    />
)

 

Edited by Fadanabela
Removed styled-components to make it cleaner.
Link to comment
Share on other sites

Hi and welcome to the GreenSock forums.

 

Sorry to hear about the struggles. I have three things to say/ask about it.

  1. Have you checked the documentation regarding the use of GSAP via NPM? Take a look at it:
    https://greensock.com/docs/NPMUsage
  2. Related to the previous point. I don't see any GSAP code in your snippet. What exactly are you trying to do? Have you tried that code in an isolated React project, that doesn't include Gatsby? As far as I know Gatsby shouldn't interfere at all with GSAP in a React project, but just in case.
  3. Have you read this?
    https://greensock.com/react
    It might help you getting started with using GSAP in a React project.

Finally if you can, please set up a reduced sample in either codesandbox or stackblitz showing your issue?

 

Happy Tweening!!

  • Like 3
Link to comment
Share on other sites

Hi!

 

I read all the articles. Yes, I know it should work Gatsby being React, but the thing is that I need it to work with the GraphQL data (if possible) and I don't know how to do that. I am also familiar with npm.

 

I did not put the Gsap code in there because it didn't work, so I thought it was useless. I basically tried everything I could think of. In the code below, I changed the component to a class and put the ref in the Gsap method.

 

I get the following error: 

TypeError: Cannot read property 'data' of undefined.

 

I tried to make the pen (as I mentioned previously), but the posts come from GraphQL, locally. Sorry for the trouble and thank you for trying to help me!

 

P.S. Please, note that I got Gsap to work in another static component. My problem is when the data is coming from GraphQL.

 

class Gallery extends Component {

    constructor(props){
        super(props);
        this.myTween = new TimelineLite({paused: false});
      }
      
      componentDidMount(){
        this.myTween.staggerTo(this.myElement, 1.5, {y: 0, autoAlpha: 1}, 0.1);
      }

      render(){
        return (
            <Wrapper>
            <Title>
                Works
            </Title>
                <Inner>
                {this.data.allMarkdownRemark.edges.map(({ node }) => (
                    <div key={node.id} ref={div => this.myElement = div}>
                        <StyledLink to={node.fields.slug}>
                            <StyledImg fluid={node.frontmatter.image.childImageSharp.fluid} />
                            <PostTitle>
                            {node.frontmatter.title}{" "}
                            </PostTitle>
                        </StyledLink> 
                        <Date>
                            {node.frontmatter.date}
                        </Date>
                        <p>{node.excerpt}</p>
                    </div>
                ))}
                </Inner>
            </Wrapper>
        )
    }
}

  export default props => (
      
    <StaticQuery
    query={graphql`
      query {
          allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
              totalCount
              edges {
              node {
                  id
                  frontmatter {
                  title
                  date(formatString: "DD MMMM, YYYY")
                  image {
                  childImageSharp {
                      fluid(maxWidth: 800) {
                      ...GatsbyImageSharpFluid_noBase64
                      }
                  }
              }
                  }
                  fields {
                  slug
                  }
                  excerpt
              }
              }
          }
          }
    `}
    render={data => <Gallery data={data} {...props} />}
    />
)

 

Link to comment
Share on other sites

Well, based on the error you're reporting and the code you posted the only source for that particular error I can spot is this:

 

{this.data.allMarkdownRemark.edges.map(({ node }) => (
  <div key={node.id} ref={div => this.myElement = div}>
  	<StyledLink to={node.fields.slug}>
  	  <StyledImg fluid={node.frontmatter.image.childImageSharp.fluid} />
  	  <PostTitle>
  	    {node.frontmatter.title}{" "}
  	  </PostTitle>
  	</StyledLink> 
    <Date>
      {node.frontmatter.date}
    </Date>
    <p>{node.excerpt}</p>
  </div>
))}

 

Where this is undefined. As far as I can see this is not an error with GSAP but some other part of your implementation. The odd thing here is the fact that this is undefined, when it should be the React instance.

 

I'll guess that you're getting your data asynchronously. In that case after the server response your data should be ready to use. Perhaps use some conditional logic inside the render method:

 

render(){
  if ( this.props.data ) {
    <Wrapper>
      <Title>
        Works
      </Title>
      <Inner>
        {this.props.data.allMarkdownRemark.edges.map(({ node }) => (
          <div key={node.id} ref={div => this.myElement = div}>
            <StyledLink to={node.fields.slug}>
              <StyledImg fluid={node.frontmatter.image.childImageSharp.fluid} />
              <PostTitle>
                {node.frontmatter.title}{" "}
              </PostTitle>
            </StyledLink>
            <Date>
              {node.frontmatter.date}
            </Date>
            <p>{node.excerpt}</p>
          </div>
        ))}
      </Inner>
    </Wrapper>
  }
  else {
    return <Wrapper>
      <Title>
        Works
      </Title>
    </Wrapper>;
  }
}

 

Finally keep in mind that you're passing the data to the Gallery component as a property, there you can't look for this.data, it has to be this.props.data

 

Happy Tweening!!

  • Like 4
Link to comment
Share on other sites

Hi...

 

I had tried using 'this' and 'this.props', but I got the same error.

Unfortunately, the conditional rendering didn't work either.

 

I still think it is a problem with the way 'data' is passed from GraphQL.

 

I will keep trying because I really want this to work!

If I find a solution, I will post here.

 

Thank you!! :)

  • Like 1
Link to comment
Share on other sites

Done.

Thank you! ??

 

import React, { Component } from "react";
import { TweenMax } from "gsap";
import { Link, graphql, StaticQuery } from 'gatsby'
import styled from 'styled-components'
import Img from 'gatsby-image'

const Wrapper = styled.div`
    margin: auto;
` 

const Title = styled.h3`
    display: inline-block;
    margin-bottom: 1rem;
`

const Inner = styled.div`
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    grid-column-gap: 40px;
    
    @media (max-width: 1024px) {
        grid-template-columns: 1fr;
        grid-column-gap: 40px;
    }
`

const StyledLink = styled(Link)`
    font-family: brandon-grotesque, serif;
    font-weight: 700;
    text-decoration: none;
    color: inherit;
`

const StyledImg = styled(Img)`
    border-radius: 7px;
    margin-bottom: 1rem;

    opacity: 1;
	-webkit-transition: .5s ease-in-out;
    transition: .5s ease-in-out;
    
        :hover {
            opacity: .7;
        }
`

const PostTitle = styled.h6`
    margin-bottom: 0.5rem;

`
const Date = styled.p`  
    font-size: 0.8rem;
    display: block;
    color: #777;
 
`


export class Gallery extends Component {
      
      componentDidMount(){
        TweenMax.staggerFrom('.box', 1.5, {y: 120, autoAlpha: 1}, 0.3);
      }

      render(){
        return (
            <Wrapper>
            <Title>
                Works
            </Title>
                <Inner>
                {this.props.data.allMarkdownRemark.edges.map(({ node }) => (
                    <div key={node.id} ref={div => this.myElement = div} className='box'>
                        <StyledLink to={node.fields.slug}>
                            <StyledImg fluid={node.frontmatter.image.childImageSharp.fluid} />
                            <PostTitle>
                            {node.frontmatter.title}{" "}
                            </PostTitle>
                        </StyledLink> 
                        <Date>
                            {node.frontmatter.date}
                        </Date>
                        <p>{node.excerpt}</p>
                    </div>
                ))}
                </Inner>
            </Wrapper>
        )
    }
}

  export default props => (
      
    <StaticQuery
    query={graphql`
      query {
          allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
              totalCount
              edges {
              node {
                  id
                  frontmatter {
                  title
                  date(formatString: "DD MMMM, YYYY")
                  image {
                  childImageSharp {
                      fluid(maxWidth: 800) {
                      ...GatsbyImageSharpFluid_noBase64
                      }
                  }
              }
                  }
                  fields {
                  slug
                  }
                  excerpt
              }
              }
          }
          }
    `}
    render={data => <Gallery data={data} {...props} />}
    />
)

 

  • Like 1
Link to comment
Share on other sites

Good to hear that you solved your issue.

 

Just keep in mind that you're using GSAP internal class selector to get your element directly from the DOM and that this code runs only when the component is mounted. If your data is updated after the componentDidMount callback, the animation won't run again and the GSAP instance will have reference to all the elements present in the DOM before the data update. If you want to animate your elements just once, then this approach, although not complying with React's recommended practice, does work.

 

Happy Tweening!!

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...