Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using the callback ref on animated element (React Spring) causes a cleanup ↻ install loop #6

Open
peeke opened this issue May 25, 2020 · 5 comments
Labels
bug Something isn't working

Comments

@peeke
Copy link

peeke commented May 25, 2020

When you pass the ref useElementSize gives you to an animated.div (react-spring), it'll trigger some infinite logic, causing the observer callback to get called over and over. Interestingly, the createObserver function is not called again.

This code triggers the issue:

function Stretch() {
  const { size: { width }, ref: elementRef } = useElementSize()
  const animatedProps = useSpring({
    opacity: 300 / Math.max(1, width)
  })

  return (
    <animated.div ref={elementRef} className={styles.componentStretch} style={animatedProps}/>
  )
}

This doesn't:

function Stretch() {
  const { size: { width }, ref: elementRef } = useElementSize()
  const animatedProps = useSpring({
    opacity: 300 / Math.max(1, width)
  })

  return (
    <div ref={elementRef}>
      <animated.div className={styles.componentStretch} style={animatedProps}/>
    </div>
  )
}
@peeke peeke added the bug Something isn't working label May 25, 2020
@EECOLOR
Copy link
Member

EECOLOR commented May 26, 2020

Does the width or height value change at all during this loop?

@EECOLOR
Copy link
Member

EECOLOR commented May 26, 2020

Can you create an example in a branch with this behavior?

@peeke
Copy link
Author

peeke commented May 26, 2020

Yes, I've pushed issue-6, containing the example above. You'll see the console.log('observer cb', entry.contentRect.width) statement executing very often.

The width of the element is not animated. Seems like it has something to do with how React Spring handles refs on animated elements.

@EECOLOR
Copy link
Member

EECOLOR commented May 29, 2020

Ok, so I narrowed it down to this:

import { animated } from 'react-spring'

export default function App() {
  const [bool, setBool] = React.useState(false)
  const ref1 = React.useCallback(node => { console.log('ref1', node) }, [])
  const ref2 = React.useCallback(node => { console.log('ref2', node) }, [])
  return (
    <div>
      <div ref={ref1}>1</div>
      <animated.div ref={ref2}>2</animated.div>
      <button onClick={() => setBool(x => !x)}>Rerender</button>
    </div>
  )
}

Output on first render is this:

ref1 <div>​1​</div>​
ref2 <div>​2​</div>​
ref2 <div>​2​</div>​

On subsequent clicks:

ref2 null
ref2 null
ref2 <div>​2​</div>​
ref2 <div>​2​</div>​

So there is a clear behavior difference. We can solve half of the problem by checking if the same node is supplied twice. Getting a null however is weird. I think we should create a CodePen (or similar) and file a ticket at react-spring.

@EECOLOR
Copy link
Member

EECOLOR commented Jun 2, 2020

I created a ticket for react-spring: pmndrs/react-spring#1037

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants