delayRender() and continueRender()
By calling delayRender()
, you are signaling that a frame should not be immediately rendered and instead should wait on an asynchronous task to complete.
This method is useful if you want to call an API to fetch data before you render.
delayRender()
returns a handle. Once you have fetched data or finished the asynchronous task, you should call continueRender(handle)
to let Remotion know that you are now ready to render.
Example
tsx
import {useCallback ,useEffect ,useState } from "react";import {continueRender ,delayRender } from "remotion";export constMyVideo = () => {const [data ,setData ] =useState (null);const [handle ] =useState (() =>delayRender ());constfetchData =useCallback (async () => {constresponse = awaitfetch ("http://example.com/api");constjson = awaitresponse .json ();setData (json );continueRender (handle );}, []);useEffect (() => {fetchData ();}, []);return (<div >{data ? (<div >This video has data from an API! {JSON .stringify (data )}</div >) : null}</div >);};
tsx
import {useCallback ,useEffect ,useState } from "react";import {continueRender ,delayRender } from "remotion";export constMyVideo = () => {const [data ,setData ] =useState (null);const [handle ] =useState (() =>delayRender ());constfetchData =useCallback (async () => {constresponse = awaitfetch ("http://example.com/api");constjson = awaitresponse .json ();setData (json );continueRender (handle );}, []);useEffect (() => {fetchData ();}, []);return (<div >{data ? (<div >This video has data from an API! {JSON .stringify (data )}</div >) : null}</div >);};
Timeout
You need to call continueRender()
within 30 seconds of page load. This is the default timeout of puppeteer and it will throw if you miss to call continueRender()
. You can customize the timeout.
If continueRender()
is not called within the timeout frame, the render will fail with an exception similarly to this:
A delayRender() was called but not cleared after 28000ms. See https://remotion.dev/docs/timeout for help. The delayRender was called
A delayRender() was called but not cleared after 28000ms. See https://remotion.dev/docs/timeout for help. The delayRender was called
See the Timeout page to troubleshoot timeouts.
Adding a label
Available from v2.6.13
If you encounter a timeout and don't know where it came from, you can add a label as a parameter:
tsx
delayRender ("Fetching data from API...");
tsx
delayRender ("Fetching data from API...");
If the call times out, the label will be referenced in the error message:
Uncaught Error: A delayRender() "Fetching data from API..." was called but not cleared after 28000ms. See https://remotion.dev/docs/timeout for help. The delayRender was called
Uncaught Error: A delayRender() "Fetching data from API..." was called but not cleared after 28000ms. See https://remotion.dev/docs/timeout for help. The delayRender was called
Concurrency
Multiple pages are used for rendering, so delayRender() can be called multiple times for a render. If you are doing an API request, you can speed up the render and avoid rate limits by caching the request, for example by storing the data in localStorage
.
Multiple calls
You can call delayRender()
multiple times. The render will be blocked for as long as at least one blocking handle exists and that has not been cleared by continueRender()
.
tsx
import {useEffect ,useState } from "react";import {continueRender ,delayRender } from "remotion";constMyComp :React .FC = () => {const [handle1 ] =useState (() =>delayRender ());const [handle2 ] =useState (() =>delayRender ());useEffect (() => {// You need to clear all handles before the render continuescontinueRender (handle1 );continueRender (handle2 );}, []);return null;};
tsx
import {useEffect ,useState } from "react";import {continueRender ,delayRender } from "remotion";constMyComp :React .FC = () => {const [handle1 ] =useState (() =>delayRender ());const [handle2 ] =useState (() =>delayRender ());useEffect (() => {// You need to clear all handles before the render continuescontinueRender (handle1 );continueRender (handle2 );}, []);return null;};
Encapsulation
You should put delayRender()
calls inside your components rather than placing them as a top-level statement, to avoid blocking a render if a different composition is rendered. Also, in the example below the call is wrapped in a useState()
to avoid creating multiple blocking calls when the component rerenders.
❌ Don't do thistsx
import {useEffect } from "react";import {continueRender ,delayRender } from "remotion";// Don't call a delayRender() call outside a component -// it will block the render if a different composition is rendered// as well as block the fetching of the list of compositions.consthandle =delayRender ();constMyComp :React .FC = () => {useEffect (() => {continueRender (handle );}, []);return null;};
❌ Don't do thistsx
import {useEffect } from "react";import {continueRender ,delayRender } from "remotion";// Don't call a delayRender() call outside a component -// it will block the render if a different composition is rendered// as well as block the fetching of the list of compositions.consthandle =delayRender ();constMyComp :React .FC = () => {useEffect (() => {continueRender (handle );}, []);return null;};