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

<Image/> component #29

Closed
JonnyBurger opened this issue Feb 9, 2021 · 8 comments
Closed

<Image/> component #29

JonnyBurger opened this issue Feb 9, 2021 · 8 comments
Assignees

Comments

@JonnyBurger
Copy link
Member

JonnyBurger commented Feb 9, 2021

Using normal HTML tags has the disadvantage that the image might not yet be loaded when Remotion is ready. I am thinking of adding a simple component which will hook into the onLoad event and wait for all images to be loaded using delayRender.

You can subscribe to this issue to follow the progress.

Solution for now:

import {useCallback, useState} from 'react';
import {continueRender, delayRender} from 'remotion';

export const Img: React.FC<Omit<
	React.DetailedHTMLProps<
		React.ImgHTMLAttributes<HTMLImageElement>,
		HTMLImageElement
	>,
	'onLoad'
>> = (props) => {
	const [handle] = useState(() => delayRender());

	const onLoad = useCallback(() => {
		continueRender(handle);
	}, [handle]);

	return <img {...props} onLoad={onLoad} />;
};
@JonnyBurger JonnyBurger self-assigned this Feb 9, 2021
@pomber
Copy link
Contributor

pomber commented Feb 9, 2021

Maybe iframes have a similar problem? They consistently disappear in some frames. Here's an example.

@JonnyBurger
Copy link
Member Author

Good point! Let's also make an IFrame component then.

Can you try if this <IFrame> component solves your problem?

import {useCallback, useState} from 'react';
import {continueRender, delayRender} from 'remotion';

export const IFrame: React.FC<Omit<
	React.DetailedHTMLProps<
		React.IframeHTMLAttributes<HTMLIFrameElement>,
		HTMLIFrameElement
	>,
	'onLoad'
>> = (props) => {
	const [handle] = useState(() => delayRender());

	const onLoad = useCallback(() => {
		continueRender(handle);
	}, [handle]);

	return <iframe {...props} onLoad={onLoad} />;
};

I'll then add it to Remotion Core, add documentation and improve DX by adding an ESLint Rule to the Remotion plugin!

@pomber
Copy link
Contributor

pomber commented Feb 9, 2021

Awesome, that fixed the iframe flickering, thanks!

For other cases, maybe you can hide the handle, delayRender, and continueRender details inside one hook:

function useResumer() {
  const [handle] = useState(() => delayRender());

  const resumeRender = useCallback(() => {
    continueRender(handle);
  }, [handle]);

  return resumeRender;
}

or something like that.

@jeetiss
Copy link
Contributor

jeetiss commented Feb 9, 2021

Hey @JonnyBurger awesome project!

I think that suspense can help with this issue!

We can create custom suspense catcher and delayRender inside, like this

import {continueRender, delayRender} from 'remotion';

class VideoSuspense extends Component {
  constructor () {
    this.state = {
      loading: false
    }
  }
  
  componentDidCatch(promise) {
    if (isPromise(promise)) {
      this.setState({ loading: true })
      delayRender()
      promise.then(() => {
        this.setState({ loading: true })
        continueRender()
      })

    } else {
      throw promise
    }
  }

  render () {
    return this.state.loading ? null : this.props.children
  }
}



// root

<VideoSuspense>
  <Video/>
</VideoSuspense>

it should be better, because we don't need to wrap components that already support suspense with remotion delayRender/continueRender, and can use existed ones

what do you think about that? I can help with implementation

@JonnyBurger
Copy link
Member Author

@jeetiss If that is possible using Suspense, then that's definitely preferrable!

But how does it work? Where does that promise come from? How do we hook into the onLoad function of img, iframe component?

@JonnyBurger
Copy link
Member Author

Since a lot of people are affected, I am going ahead with the original plan and will merge #32. There is now also an ESLint rule enabled which will warn you if you use the native or <iframe> component!

@JonnyBurger
Copy link
Member Author

Fixed by #32

@jeetiss
Copy link
Contributor

jeetiss commented Feb 10, 2021

@JonnyBurger, yes ofc! i am going to open new issue for suspense

But how does it work?

I'm not the best explainer) super simple scheme:

  • Component loads some resource and throws a promise
  • ErrorBoundary catch this promise and wait until it resolves and continue render

Where does that promise come from?

Components throw them:

iframe component?

Iframe component is not so trivial for suspense, but can be implemented with hacks:
https://gist.github.com/threepointone/e73a87f7bbbebc78cf71744469ec5a15

Suspense is still experimental, but react community have a lot components that supports this feature
So i think it fit great for remotion

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants