Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
flowen

React hook useEffect + greensock - antipattern

Recommended Posts

  /**
   * setup Gsap animation
   */
  useEffect(() => {
    if (
      !refWrapperLarge.current ||
      !refWrapperSmall.current ||
      !refWrapperBorder.current ||
      !refText.current ||
      !refRectLargeRight.current
    )
      return

      // animation code
  }, [
    refWrapperLarge.current,
    refWrapperSmall.current,
    refWrapperBorder.current,
    refText.current,
    refRectLargeRight.current,
  ])

 

This month I've been coding a lot in React hooks (in Gatsby env) with GSAP. 

 

But I keep coming across the above (anti-)pattern. I wondered if perhaps someone had a better solution or idea how this could be done. 

 

So if you're not familiair with the useEffect hook, it's a piece of code that keeps re-running when for examples values (or state) changes. 

Which can be super-useful in apps. 

 

But in order to animate elements with GSAP, I kept coming back to this pattern.  I first need to check if all refs exists (they're primarily defined with the useRef() hook). 

On the first run they do not, since the component is still being rendered.

In the dependency array I add the refs as well, so it will re-run, until all DOM elements exists.

 

Only then can I start animating the components. 

 

@Rodrigo you have any idea/suggestion?

Link to comment
Share on other sites

I'll take a look at it a bit later. Perhaps is something related to the newer versions of React or specific of Gatsby, although I found the latte more improbable, since the warning (I assume that you're getting a warning in the console) should be comming from React.

 

Another chance is to check the conditions with && instead of || since if one of the conditions is falsy but the rest are truthy the entire conditional block returns true:

var a, b; // both are undefined at this point

b = 1;

// a is undefined it returns truthy, b is defined returns falsy
// the entire block returns false
if (!a || !b) // -> false

// the entire block returns true
if (!a && !b) // -> true

Try that and let us know if there is any difference, I'll check some samples here in my machine and see what comes out of it.

 

Happy Tweening!!!

  • Like 3
Link to comment
Share on other sites

  • 1 year later...

Personally, I've found that using regular CSS selectors with gsap in React (also using Gatsby over here) is a hell of a lot easier than messing with refs. You still need to include all the to's and set's and such inside of useEffect hooks (otherwise no elements would have been rendered yet to select), but I have yet to encounter a case where refs worked where selectors didn't...

 

Also wondering about the difference between the following two methods, if any:

 
const Component = () => {
  let ref = null
  return (
    <div ref={ e => (ref = e) } />
  )
}
 
const Component = () => {
  const ref = useRef(null)
  return (
    <div ref={ ref } />
  )
}
 

 

Link to comment
Share on other sites

The only issue with using regular CSS selectors is that you can get caught out if your components share classnames/attributes.

 

With regards to refs, according to the docs, the callback ref gives you finer control over when to set the ref for an element. However, I've yet to find an instance where I've needed this for GSAP. I usually use a ref pattern. I have been playing with proof of concept pieces for how to create convenience components for React && GSAP 👍 The issue faced is how/what would be the nicest way to expose GSAP in React whilst still providing all the benefits. I think timelines could likely still live in effects. But, there are some different directions it could go in. Custom hooks, <GSAP.div yoyo duration={2}/>, <To scale={2}><div/></To>. 

  • Like 3
Link to comment
Share on other sites

When I first tried integrating gsap into my react project, I gave this a shot: https://github.com/bitworking/react-gsap 

It claims to function with styled-components, but it doesn't, really, or at least didn't for me, I had to wrap my styled components in plain HTML ones to get this to work. That alone made it too much of a pain to continue working with...

Link to comment
Share on other sites

Which version of styled components are you using?

 

Styled Components' API do grant access to the DOM node in the component using refs:

 

https://styled-components.com/docs/advanced#refs

 

Now in some cases there shouldn't be too much of an issue using regular selectors in Gatsby/Next projects, just be sure that the content in the page/component is completely static and that is generated in the server using SSR. In those cases nothing will change in the DOM tree after the server renders the page and sends it to the client. 

 

@jh3y that was an idea that I entertained for a while, but at the end it's far easier and simpler to just use GSAP in a regular fashion than create a set of components that handle all the DOM node operations for you. At the end you still need to access the ref and what happens if, for example, you need to animate a nested SVG tag with inline attributes, in that case you have to wrap the component with the GSAP one and still clone it and go through all that which is a lot of hassle for that. IMHO is best for people to stop demonizing the fact that using imperative code in React apps is the devil's work, it's just JS that, if used correctly and safely, doesn't have any security or another side effects. Of course this is just my two cents on the subject, if you feel that creating something like that fills a void in the current React+GSAP scenario in the web, then go ahead and dive into it, we'll be here to help as much as possible in the process.

 

Happy Tweening!!!

  • Like 3
Link to comment
Share on other sites

17 hours ago, jh3y said:

I usually use a ref pattern. I have been playing with proof of concept pieces for how to create convenience components for React && GSAP 👍 

 

I mean, I state that I usually use a `ref` pattern. But, I always use a ref pattern.

 

I threw a concept demo for it together maybe yesterday though to see how it might look. I think for those comfortable, it's not necessary. It's using the DOM afterall. The rule, keep a handle on your state updates.

 

That said, although some are comfortable, it doesn't mean that everyone is comfortable. And for convenience things, a lot of people reach for tools like Framer arguably because of that. They have a component that they drop in, throw some props on, and they're done. 

 

It's easy to take a skillset for granted and assume others have that same skill. But, if conveniences were offered to users, it would perhaps act as a gateway for those who want to explore more advanced GSAP usage who then look further at using refs more extensively.

 

An example library that does this, React and ThreeJS. We could write all our ThreeJS code ourselves in an effect. However, React Three Fiber exists with convenience hooks and components to create meshes, etc.

 

I guess what I'm getting at is that I wouldn't dismiss providing things like that for users if it were a stepping stone to using GSAP more extensively. Of course, only my thoughts and observations.

 

17 hours ago, billyZduke said:

When I first tried integrating gsap into my react project, I gave this a shot: https://github.com/bitworking/react-gsap 

It claims to function with styled-components, but it doesn't, really, or at least didn't for me, I had to wrap my styled components in plain HTML ones to get this to work. That alone made it too much of a pain to continue working with...

As mentioned above. `innerRef` or `ref` depending on your Styled Components version should get the job done. I'd be happy to look at a demo if you have one though 👍

 

It should work the same as a normal element.

 

const Spinner = styled.div`
  height: 25vmin;
  width: 25vmin;
  border-radius: 50%;
  border: 2vmin solid hsl(90, 80%, 60%);
  border-left-color: transparent;
  border-right-color: transparent;
`

const App = () => {
  const spinnerRef = useRef(null)
  useEffect(() => {
    gsap.to(spinnerRef.current, {
      rotation: 360,
      repeat: -1,
      ease: 'none'
    })
  }, [])
  return (
    <Spinner ref={spinnerRef}/>
  )
}

 

See the Pen oNYQVrP by jh3y (@jh3y) on CodePen

 

  • Like 3
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.
×