Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to prevent re-rendering when <Timeline /> playState changes? #36

Open
capi1O opened this issue Feb 10, 2021 · 1 comment
Open

How to prevent re-rendering when <Timeline /> playState changes? #36

capi1O opened this issue Feb 10, 2021 · 1 comment
Labels
help wanted Extra attention is needed

Comments

@capi1O
Copy link

capi1O commented Feb 10, 2021

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.

@capi1O
Copy link
Author

capi1O commented Feb 11, 2021

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>
};

@bitworking bitworking added the help wanted Extra attention is needed label Mar 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants