0

I'm trying to create animated text in React (typescript) using GSAP.

Text variable is a string, which is split into an array of strings, form which separate div's are created for every letter. In order to get this animated with GSAP, every element needs to have its own ref - for now only last letter works as only one ref is assigned.

How to create separate refs for every element and pass them to gsap? Seen somewhere that I should pass a callback as refs, but I'm not sure how to do that.

const TextAnimator: FC<TextAnimatorTypes> = ({ text }) => {
    const animatedLetter = useRef(null);

    const letterArray = text.split('');
    const letterElements = [];
    for (let i = 0; i < letterArray.length; i++) {
        letterElements.push(<div ref={animatedLetter} className={styles.letter}>{letterArray[i] === ' ' ? '\xa0' : letterArray[i]}</div>);
    }

    useEffect(() => {
        const random = (min: number, max: number) => {
            return (Math.random() * (max - min)) + min;
        };

        gsap.from(animatedLetter.current, {
            duration: 2.5,
            opacity: 0,
            x: 0,
            y: random(-200, 200),
            z: random(500, 1000),
            scale: .1,
            delay: 0.2,
            yoyo: true,
            repeat: -1,
            repeatDelay: 4,
            ease: Power1.easeOut
        });
    }, []);

    return (
        <div className={styles.box}>
            <p className={styles.animatedText}>
                {letterElements}
            </p>
        </div>
    );
};
3
  • Does this answer your question? stackoverflow.com/questions/54940399/… Commented Mar 23, 2020 at 1:11
  • Why not use GSAP's SplitText which returns an array of references to all of the letters? Commented Mar 23, 2020 at 15:01
  • Zach, GSAP split text is a paid add-on I'm afraid. And, as far as I know, all it does is wrap letters in div's :( Commented Mar 23, 2020 at 15:28

1 Answer 1

0

There is a workaround I've figured out, but still would prefer the useRef hook if someone knows the way to do it...

const TextAnimator: FC<TextAnimatorTypes> = ({ text }) => {
    const letterArray = text.split('');
    const letterElements = [];
    const elementIds: string[] = [];
    for (let i = 0; i < letterArray.length; i++) {
        letterElements.push(<div className={styles.letter}
                                 id={letterArray[i] + i}>{letterArray[i] === ' ' ? '\xa0' : letterArray[i]}</div>);
        elementIds.push(letterArray[i] + i);
    }

    const random = (min: number, max: number) => {
        return (Math.random() * (max - min)) + min;
    };

    useEffect(() => {
        for (let i = 0; i < elementIds.length; i++) {
            const element = document.getElementById(elementIds[i]);
            gsap.from(element, {
                duration: 2.5,
                opacity: 0,
                x: random(-500, 500),
                y: random(-500, 500),
                z: random(-500, 500),
                scale: .1,
                delay: i * .02,
                yoyo: true,
                repeat: -1,
                repeatDelay: 10,
                ease: Power1.easeOut
            });
        }
    }, [elementIds]);

    return (
        <div className={styles.box}>
            <p className={styles.animatedText}>
                {letterElements}
            </p>
        </div>
    );
};
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.