Jump to content
Search Community

React, question about Refs and staggerTo

m4rsibar 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

i'm wondering how to use staggerTo when the mapping is happening in a separate component. 

not sure if i'm asking this in a way that makes sense, because im not  entirely sure how staggerTo is working, but i've managed to get it to work... the problem is i've since separated the components in my app for readability and it's broken now.

 

 

Before i moved the component it looked something like this(leaving out irrelevant code)

 

class App extends Component{

 

   lis= [ ]

   

    state={   

         liText: ["My Work", "About Me"]

}

 

this.tl
.staggerTo(this.lis, 0.9, { opacity: 1, x: 20 }, "prev+=.9")
this.tl.play();
}

 

render() {
return (
   
<Nav ref={div => (this.nav = div)}>
  Logo
  <ul>
  {// map through the elements
  this.state.liText.map((element, index) => (
  <a href="#">
  <li key={index} ref={li => (this.lis[index] = li)}>
  {element.li}
  </li>
  </a>
  ))}
  </ul>
  <Logo />
  </Nav>
    )
}

 

}

 

the new separated nav component looks like this: 

 

const Navigation = React.forwardRef((props, ref) => {
return (
<Nav ref={ref}>
Logo
<ul>
{// map through the elements
props.liText.map((element, index) => (
<a href="#">
<li key={index} ref={li => (props.lis[index] = li)}>
{element.li}
</li>
</a>
))}
</ul>
</Nav>
);
});
 
export default Navigation
 
*styled-component stuff down here*
 

 

 

and the App.js looks the same except for this 

 

<Navigation
liText={this.state.liText}
lis={this.lis}
ref={div => (this.nav = div)}
/>

 

 

Link to comment
Share on other sites

Hi,

 

First of all the post editor has an option to include code snippets, is the button with the smaller and bigger than icon <>, it has syntax highlighting and auto-detects indentation. That makes reading code easier and faster, please do your best effort to use it.

 

In the react aspect of your issue, yeah that's a pickle. React has the forward refs feature that allows to create a reference to the DOM node of a child component in it's parent, but in the case of an array of DOM nodes I'm pretty sure is not going to work.

 

My advice would be to create the reference in the child component and store in the instance the array of DOM nodes. Then create a method to simply return that array:

 

// Child component
constructor (props) {
  super(props);
  this.navEls = [];
  this.getNavElements = this.getNavElements.bind(this);
}

getNavElements () {
  return this.navEls;
}

render () {
  return <nav>
    {array.map( (element, index) => <li ref={li => this.navEls[index] = li}></li>)}
  </nav>;
}

 

In the parent component use a regular createRef method to get a reference to the child component and execute the method that returns the array, then store it in the state:

 

// parent component
constructor (props) {
  super(props);
  this.myNav = React.createRef();
  this.state = {
    navElements: []
  };
}

componentDidMount () {
  this.setState({
    navElements: this.myNav.current.getNavElements()
  });
}

render () {
  return <div>
    <Navigation ref={this.myNav} />
  </div>;
}

 

Then you can use componentDidUpdate to create the animation or you can also do it directly in the componentDidMount method, is up to you actually.

 

Here is a simple live sample:

 

https://stackblitz.com/edit/react-gsap-staggerlist-in-child-component

 

Happy Tweening!!!

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

Is there anyway you could help me figure out what I'm doing wrong @Rodrigo?
Here i'm trying to separate out the Scroll component into it's own file and have a reference of it in the app component so the tweening can take place... i've been stuck on this concept for a while now ?

 

import React, { Component } from "react";
import "./App.scss";
import styled, { keyframes } from "styled-components";
import { TweenMax, TweenLite, Power2, TimelineLite } from "gsap";
import Scroll from "./ScrollSpy";

class App extends Component {
  scroll = React.createRef();

  componentDidMount() {
    this.tl
      .staggerTo(this.welcomeTxt, 0.9, { opacity: 1, y: 70 }, 0.1)
      .staggerTo(
        this.welcomeTxt,
        0.9,
        { visibility: "visible", opacity: 0, delay: 0.5 },
        "prev"
      )
      .to(this.name, 0.9, { y: 350, x: -400 }, "prev+=.5")
      .to(this.nav, 0.9, { opacity: 1 }, "prev+=.5")
      .to(this.hero, 0.9, { opacity: 1 }, "p rev+=.9")
      .staggerTo(this.lis, 0.9, { opacity: 1, x: 20 }, "prev+=.9")
      .to(this.music, 0.9, { opacity: 1 }, "prev+=2")
      .to(this.scroll, 0.9, { visibility: "visible" }, "prev+=2");

    this.tl.play();
  }

  render() {
    return (
     
        <Scroll ref={this.scroll} />
    );
  }
}

export default App;

 

I've removed a lot of code for ease of reading

and the Scroll component is here: 

import React, { component } from "react";
import { BrowserRouter, Route } from "react-router-dom";
import styled from "styled-components";

const Scroll = React.forwardRef((scroll, ref) => (
  <ScrollSpy ref={ref}>
    <div className="one" />
    <div className="two" />
    <div className="three" />
  </ScrollSpy>
));

const ScrollSpy = styled.div`
  visibility: hidden;
  grid-column: 11/13;
  grid-row: 6/9;
  display: flex;
  ${"" /* flex-direction: column; */}
  justify-content: center;
  & .one {
    height: 10px;
    width: 10px;
    background: black;
    border-radius: 50%;
    margin-right: 0.5em;
  }
  & .two,
  .three {
    height: 10px;
    width: 10px;
    background: transparent;
    border: 0.5px solid black;
    border-radius: 50%;
    margin-right: 0.5em;
  }
`;

export default Scroll;


 

 

Link to comment
Share on other sites

Is basically the same issue as before. This:

 

<Scroll ref={this.scroll} />

 

Will create a reference to a React component instance, not a DOM node because the forwarded ref goes into another component:

 

<ScrollSpy ref={ref}>
    <div className="one" />
    <div className="two" />
    <div className="three" />
</ScrollSpy>

 

This is basically whatever styled components (which is a tool that I have never used) returns. That most likely will be another React Component and not a DOM node. You could try to log <ScrollSpy> into the console and find out what that is. Your best choice is look up in the styled components API for a way to retrieve the DOM node created in order to access that and create the animation.

 

Honestly I understand the usage of styled components by developers but personally I don't see any upside to it. Call me an old school guy, but I prefer my styles and my JS code in different files.

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