Jump to content
Search Community

Accessing ref for tween(React GSAP)

Alexander75 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

https://codesandbox.io/s/z21pkzpjkp

 

 

I'm trying to recreate something I saw someone make, but in React. I'm running into a problem when attempting to animate.  

As you can see in the code sandbox,  I have a card component. 

 

In the About.js the card component is rendered through mapping over an array that has the  independent information to inject into the cards.

 

The refs I need to access are created in the function "createCards"

 

createCards(card, i) {
    return (
      <Card
        id={i}
        key={i}
        card={card}
        info={this.state.aboutCards}
        ref={card => {
          this["card" + i] = card;
        }}
      />
    );
  }
}

So 3 references are made,  card0, card1, and card2.

 

Those are the refs I need to access, but I want to access them in Card.js if thats possible. 
So I can create a timeline and do all of the animations over there, because i'll be animating the image, and header. 

 

When i'm in Card.js and console.log(this.refs) in the component did mount I get 3 objects.


The problem is i'm not sure how to use them in Card.js for example: 

 

class Card extends Component {
  tl = new TimelineLite({ paused: true });
  *i dont know how to initalize as null here*

  componentDidMount() {
    this.tl.to("i dont know what to put here", 0.9, { y: 350, x: -400 }, 0.2);
  }

  render() {

 

 

 

Or...should i be doing the animation in About.js?

 

i've tried something like this: and it's not really working either... 

 

 

 

class About extends Component {
  constructor(props) {
    super(props);
    this.createCards = this.createCards.bind(this);
    this.tl = new TimelineLite({ paused: true });
    this.card0 = null;
    this.card1 = null;
    this.card2 = null;
  }
  
  
  
  componentDidMount() {
    this.tl.to(this.card0, 0.9, { opacity: 0 });
    this.tl.play();
  }

  
  

 

 

 

See the Pen by s (@s) on CodePen

  • Like 1
Link to comment
Share on other sites

Hi and welcome to the GreenSock forums.

 

The fist thing here is that when you create a ref in directly in a component, you get the component instance and not the DOM node or tree that the component ultimately renders:

 

class MyApp extends Componetn {
  constructor(props) {
    super(props);
    
    this.myCard = null;
  }
  
  componentDidMount () {
    console.log(this.myCard); // returns a React component object
  }
  
  render () {
    return <div>
      <Card ref={card => myCard = card} />
    </div>;
  }
}

 

That because the ref callback is being called in a React Component instance and not a DOM node created in JSX.

 

Then is not clear where you want to create the animations; In the parent component or on each card?.

 

If you want to create the animations in the parent component then you should use Forwarding Refs in order to store a reference to the DOM node that sits at the top of the DOM tree created by that component. Forwarding refs is a bit of a complex resource for someone that is just staring with React, specially if your Card component can't be transformed into a functional component. If your Card component can be transformed into a functional component, then is pretty easy. This is an extremely simple example of using forward refs to create an animation with GSAP:

 

https://stackblitz.com/edit/react-forwarding-refs-gsap

 

An alternative is to use React Transition Group in order to create the animations inside each Card component. This approach can also be a bit convoluted as shown here:

https://stackblitz.com/edit/gsap-react-transition-group-list

 

Finally if you want to access the DOM element directly inside each instance of the Card component without all the hassle of React Transition Group you're very close in fact. Right now you have this on your Card component:

 

class Card extends Component {
  tl = new TimelineLite({ paused: true });

  componentDidMount() {
    console.log(this.refs);
  }

  render() {
    return (
      <div className="slide">
        <div className="card">
          <div className={`${this.props.card.id} card-img`} />
          <div className="card-content" ref>
            <p className="card-theme">{this.props.card.theme}</p>
            <h2 className="card-header">{this.props.card.header}</h2>
            <p className="card-para"> lorem lorem</p>
            <a className="card-link" href="#">
              Read
            </a>
          </div>
        </div>
        <div className="prevnext">
          <button className="pn-btn" id="prev" />
          <button className="pn-btn" id="next" />
        </div>
      </div>
    );
  }
}

 

Keep in mind that the ref is a callback that, used as an attribute in the JSX code, grabs whatever is returned from the tag where is used, in this case a <div> element, but is a function, now you're only referencing that function but you're not doing anything with it. You have to create a reference to the DOM element in the constructor and then use the callback to update it at render time:

 

class Card extends Component {
  constructor(props){
    super(props);
    this.tl = new TimelineLite({ paused: true });
    this.card = null;
  }

  componentDidMount() {
    console.log(this.card); // returns the div element
  }

  render() {
    return (
      <div className="slide">
        <div className="card">
          <div className={`${this.props.card.id} card-img`} />
          <div className="card-content" ref={div => this.card = div}>
            <p className="card-theme">{this.props.card.theme}</p>
            <h2 className="card-header">{this.props.card.header}</h2>
            <p className="card-para"> lorem lorem</p>
            <a className="card-link" href="#">
              Read
            </a>
          </div>
        </div>
        <div className="prevnext">
          <button className="pn-btn" id="prev" />
          <button className="pn-btn" id="next" />
        </div>
      </div>
    );
  }
}

 

That particular use will allow you to use the <div> element in your GSAP instance with no problems.

 

Hopefully this is enough to get you started.

 

Happy Tweening!!

  • Like 2
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...