Search code examples
javascriptreactjsreact-hooksweb-frontendgsap

React+gsap use random animation element group can't work when it complete?


I use gsap to create the animation.

When the button is clicked creates a bubble animation.

When animation is completed destroys itself.

I think the question is use map at React component but I can't find another case

Here is my React code and js fiddle example:

https://jsfiddle.net/xiaowang/ueqsg83j/58/

const { useState, useEffect, useRef } = React;

gsap.registerPlugin(MotionPathPlugin)

const Bubble = ({ onClose, data }) => {
    const pointRef = useRef(null)
    useEffect(() => {
    const path = []
    let offsetY = 0
    for(let i = 0; i < 10; i++) {
      const y = offsetY - Math.floor(Math.random() * 20 + 30)
      offsetY = y
      path.push({ x: Math.floor(Math.random() * 40 - 20), y })
    }
    gsap.to(pointRef.current, 5, {
      motionPath: {
        path,
        type: 'cubic'
      },
      onComplete: () => onClose()
    })
    return () => {}
  }, [])
    return (<span className="bubble" ref={pointRef}>{data.id}</span>)
}

const App = () => {
    const [count, setCount] = useState(0)
  const [bubbles, setBubbles] = useState([])

    const handleCreate = () => {
    setBubbles([...bubbles, {id: count}])
    setCount(count + 1)
  }

  const handleClose = index => {
    const newBubbles = [...bubbles]
    newBubbles.splice(index, 1)
    setBubbles(newBubbles)
  }

  return (
    <div className="wrap">
      {
        bubbles.map((item, index) => (
            <Bubble
            key={item.id}
            data={item}
            onClose={() => handleClose(index)} />
        ))
      }
      <button type="button" onClick={handleCreate}>Click Me</button>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('app'))


Solution

  • Not sure it will help much, but I've moved your code to the sandbox, because I couldn't find the console on jsfiddle, and made small modification to the code:

    https://codesandbox.io/s/react-and-gsap-issue-7tkrd

    Main changes are.

    Change handleClose implementation to a simple filter:

    const handleClose = id => () => {
        setBubbles(prev => prev.filter(bubble => bubble.id !== id));
      };
    

    Changed how we invoke it (and render in general):

    return (
        <div className="wrap">
          {bubbles.map(item => (
            <Bubble key={item.id} data={item} onClose={handleClose(item.id)} />
          ))}
          <button type="button" onClick={handleCreate}>
            Click Me
          </button>
        </div>
      );
    

    It has fixed the issue, if I understood your problem correctly, and I think that problem was in how you have used splice. Hope that will help.