Rom-888
Rom-888

Reputation: 876

GSAP target undefined not found

With useSate I toggle between two paragraphs of text from french to english. It works fine but I want to set up a nicer transition with GSAP.

My configuration doesn't work because the gsap target is null or undefined. Can you help me to debug that problem?

The paragraph component with the two buttons :

      import React, { useRef, useState } from "react";
import { withRouter } from "react-router-dom";
import gsap from 'gsap';

const LanguageDesc = (props) => {

    const [state, setState] = useState({
        isActive: false,
        languageName: 'English'
    });

    let english = useRef(null);
    let french = useRef(null);

    const handleLanguage = () => {
        if (state.isActive === false) {
            setState({
                isActive: true,
                languageName: 'French'
            })
            gsap.from(english.current, {
                duration: 5,
                opacity: 0,
            })
        } else if (state.isActive === true) {
            setState({
                isActive: false,
                languageName: 'English'
            })
            gsap.from(french.current, {
                duration: 1,
                opacity: 0,
            });
        } else if (state.isActive === false) {
            setState({
                isActive: !state.isActive,
                languageName: 'French'
            })
            gsap.from(english.current, {
                duration: 5,
                opacity: 0,
            })
        }
    };


    return (
        <div>
            {state.isActive ?
                <p ref={english} className="eng-text">{props.state.desc_en}</p>
                : null}
            {state.isActive ?
                null
                : <p ref={french} className="fr-text">{props.state.desc_fr}</p>}
            <button className="btn-language" onClick={handleLanguage} > {state.languageName} text</button>
        </div >
    )

};
export default withRouter(LanguageDesc);

console

Upvotes: 2

Views: 7380

Answers (1)

backtick
backtick

Reputation: 2775

The problem is ref={el => (english = el)} and the same usage for the french ref.

Refs returned by useRef are references to a single object that is held in memory across the lifetime of the component. You must read from and write to the ref using the current property.

Assigning english to the value of el does not change the value of the english ref, it replaces the ref with el. You then access the current property on the element, which (since it is not a ref) will always be undefined.

english is already a ref, so you don't need to handle the assignment yourself. Just do ref={english} and React will handle the rest.

Update

The issue remains because your code still uses the refs as elements when they are null.

When isActive is false, there is no english element. When true, no french element. Yet each event handler depends on both elements being present.

Removing the elements entirely increases the complexity of animating the in/out transitions. Maybe instead you can use isActive to determine whether to display each p element (display: none;), but always render both.

() => {
  const handleLanguage = () => {
    if (isActive) {
      gsap
        .from(french.current, {
          duration: 1,
          opacity: 0,
        })
        .eventCallback('onComplete', () => {
          setState({
            isActive: false,
            languageName: 'English',
          });
        });
    } else {
      gsap
        .from(english.current, {
          duration: 5,
          opacity: 0,
        })
        .eventCallback('onComplete', () => {
          setState({
            isActive: true,
            languageName: 'French',
          });
        });
    }
  };

  return (
    <div>
      <p
        ref={english}
        style={{ display: isActive ? 'none' : 'initial' }}
        className="eng-text"
      >
        {desc_en}
      </p>
      <p
        ref={french}
        style={{ display: isActive ? 'initial' : 'none' }}
        className="fr-text"
      >
        {desc_fr}
      </p>
      <button className="btn-language" onClick={handleLanguage}>
        {' '}
        {state.languageName} text
      </button>
    </div>
  );
};

Upvotes: 2

Related Questions