react-gsap
react-gsap copied to clipboard
How to prevent re-rendering when <Timeline /> playState changes?
I have defined my timeline as such:
const Component = () => {
const [playState, setPlayState] = useState(PlayState.pause);
return (
<Timeline
playState={playState}
labels={[{ label: 'start', position: 0 }]}
target={<Content />}
>
<Tweens />
</Timeline>
);
where <Content />
is a component using react-gsap targets.set
to set targets similarly to what is done in the examples.
I want to control my timeline playState
using useState
inside my <Component />
which contains the <Timeline />
.
But every time I change state <Content />
is re-rendered of course. The thing is my playState
depends depends on <Content />
(I wait for some elements inside <Content />
to load, then I inform <Component />
that animation can begin and setPlayState(PlayState.play)
. Because of the re-rendering it is not possible because <Content />
stuff are reloaded, the animation begins before it has fully loaded.
I don't think this is currently possible due how react-gsap is structured because content is a rendered prop of <Timeline />
. I understand this was done this way in order to be able to set the targets but IMO we should be able to separate content and animation in the React tree.
I tried to make it clear and I hope I am not doing anything too weird.
I ended up not using playState
but using low-level GSAP to control timeline play state from content.
In order to do that I had to pass the <Timeline />
ref to <Content />
. because of issue #33 I had to use a wrapper component.
import React, { useRef, forwardRef } from 'react';
import { Timeline, PlayState } from 'react-gsap';
import Content from './Content';
import Tweens from './Tweens';
const Component = () => {
const timelineRef = useRef(null);
const ContentWrapper = forwardRef<HTMLDivElement, {}>((props, targets: TargetsRef) => (
<Content targets={targets} timelineRef={timelineRef} />
));
return (
<Timeline
ref={timelineRef}
labels={[{ label: 'start', position: 0 }]}
target={<ContentWrapper />}
playState={PlayState.stop}
>
<Tweens />
</Timeline>
);
};
export default Component;
then in <Content />
I could access
const Content = ({ timelineRef: MutableRefObject<Timeline>, targets: TargetsRef }) => {
const handleClick = () => {
timelineRef.current?.getGSAP().play(0);
};
return <button ref={node => targets.set('button', node)} onClick={handleClick}>some content</button>
};