Reputation: 876
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);
Upvotes: 2
Views: 7380
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.
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