Search code examples
reactjscss-animationsreact-springreact-motion

React-spring how to animate letters of an array correctly


In this code with react-spring I am getting an animation where each letter waits until the previous animation ends, and also in the meantime it is being animated

Why is this happening, and how could I fix it?

  const text = [...'hey there how are you']
  const from = { transform: 'rotateX(0deg) translateY(0px) rotate(0deg) scale(1)' }
  const to = inView
    ? [
        { transform: 'rotateX(30deg) translateY(10px) rotate(-13deg) scale(1)' },
        { transform: 'rotateX(0deg) translateY(-22px) rotate(3deg) scale(1.1)' },
        { ...from },
      ]
    : from

  const trail = useTrail(text.length, {
    config: { mass: 5, tension: 2000, friction: 200 },
    from: from,
    to: to,
  })

  return (
    <>
      <Div ref={handleRef}>
        {trail.map((props, i) => (
          <animated.span key={`char${i}`} style={props}>
            {text[i] === ' ' ? <>&nbsp;</> : text[i]}
          </animated.span>
        ))}
      </Div>
    </>
  )

Solution

  • Using useSprings I can get independent strings for each item, which I can delay individually

    This is done out-of-the-box when the to: only has one rule, but if you want to concatenate more rules then somehow each element is not independent of the others

    Using useSprings you can get this individuality

    const text = [...'hey there how are you']
      const from = { transform: 'translate3d(0,0px,0)' }
      const to = inView ? [{ transform: 'translate3d(0,-40px,0)' }, { transform: 'translate3d(0,40px,0)' }] : from
    
      const base = {
        config: { mass: 5, tension: 2000, friction: 200 },
        from: from,
        to: to,
      }
    
      const springs = useSprings(text.length, text.map((t, i) => ({ ...base, delay: 100 * i })))
    
      return (
        <Div ref={handleRef}>
          {springs.map((s, i) => {
            return (
              <animated.span key={`char${i}`} style={s}>
                {text[i] === ' ' ? <>&nbsp;</> : text[i]}
              </animated.span>
            )
          })}
        </Div>
      )