Skip to main content

delayRender() 和 continueRender()

通过调用 delayRender(),您在表示一个帧不应立即渲染,而应等待异步任务完成。

如果您想在渲染之前调用 API 来获取数据,则此方法很有用。

delayRender() 返回一个句柄。一旦您获取了数据或完成了异步任务,应调用 continueRender(handle),以通知 Remotion 您现在已准备好进行渲染。

示例

tsx
import { useCallback, useEffect, useState } from "react";
import { continueRender, delayRender } from "remotion";
 
export const MyVideo = () => {
const [data, setData] = useState(null);
const [handle] = useState(() => delayRender());
 
const fetchData = useCallback(async () => {
const response = await fetch("http://example.com/api");
const json = await response.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 const MyVideo = () => {
const [data, setData] = useState(null);
const [handle] = useState(() => delayRender());
 
const fetchData = useCallback(async () => {
const response = await fetch("http://example.com/api");
const json = await response.json();
setData(json);
 
continueRender(handle);
}, []);
 
useEffect(() => {
fetchData();
}, []);
 
return (
<div>
{data ? (
<div>This video has data from an API! {JSON.stringify(data)}</div>
) : null}
</div>
);
};

超时

您需要在页面加载后的 30 秒内调用 continueRender()。这是 puppeteer 的默认超时时间,如果您忘记调用 continueRender(),它将抛出异常。您可以自定义超时时间

如果在超时帧内未调用 continueRender(),渲染将失败,并显示类似于以下内容的异常:

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

请查看超时页面以解决超时问题。

添加标签v2.6.13

如果遇到超时问题并且不知道其来源,可以将标签作为参数添加:

tsx
delayRender("Fetching data from API...");
tsx
delayRender("Fetching data from API...");

如果调用超时,错误消息中将引用该标签:

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

并发

用于渲染的是多个页面,因此可以多次调用 delayRender() 进行渲染。如果正在进行 API 请求,可以通过缓存请求来加快渲染速度并避免速率限制,例如通过将数据存储在 localStorage 中。

多次调用

您可以多次调用 delayRender()。只要至少存在一个阻塞句柄且尚未通过 continueRender() 清除,渲染将被阻塞。

tsx
import { useEffect, useState } from "react";
import { continueRender, delayRender } from "remotion";
 
const MyComp: React.FC = () => {
const [handle1] = useState(() => delayRender());
const [handle2] = useState(() => delayRender());
 
useEffect(() => {
// You need to clear all handles before the render continues
continueRender(handle1);
continueRender(handle2);
}, []);
 
return null;
};
tsx
import { useEffect, useState } from "react";
import { continueRender, delayRender } from "remotion";
 
const MyComp: React.FC = () => {
const [handle1] = useState(() => delayRender());
const [handle2] = useState(() => delayRender());
 
useEffect(() => {
// You need to clear all handles before the render continues
continueRender(handle1);
continueRender(handle2);
}, []);
 
return null;
};

封装

您应该将 delayRender() 调用放在组件内部,而不是将其放在顶层语句中,以避免在渲染不同组合时阻塞渲染。此外,在下面的示例中,调用被包裹在 useState() 中,以避免在组件重新渲染时创建多个阻塞调用。

❌ 不要这样做
tsx
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.
const handle = delayRender();
 
const MyComp: React.FC = () => {
useEffect(() => {
continueRender(handle);
}, []);
 
return null;
};
❌ 不要这样做
tsx
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.
const handle = delayRender();
 
const MyComp: React.FC = () => {
useEffect(() => {
continueRender(handle);
}, []);
 
return null;
};

出现错误时v3.3.44

如果您的代码未能执行异步操作并且您希望取消渲染,您可以调用带有错误消息的 cancelRender()。这将自动取消所有 delayRender() 调用,以避免进一步延迟渲染。

MyComposition.tsx
tsx
import React, { useEffect, useState } from "react";
import { cancelRender, continueRender, delayRender } from "remotion";
 
export const MyComp: React.FC = () => {
const [handle] = useState(() => delayRender("Fetching data..."));
 
useEffect(() => {
fetch("https://example.com")
.then(() => {
continueRender(handle);
})
.catch((err) => cancelRender(err));
}, []);
 
return null;
};
MyComposition.tsx
tsx
import React, { useEffect, useState } from "react";
import { cancelRender, continueRender, delayRender } from "remotion";
 
export const MyComp: React.FC = () => {
const [handle] = useState(() => delayRender("Fetching data..."));
 
useEffect(() => {
fetch("https://example.com")
.then(() => {
continueRender(handle);
})
.catch((err) => cancelRender(err));
}, []);
 
return null;
};

重试v4.0.140

如果某个操作不稳定(例如,从 CDN 加载资源有时会出现 5xx 错误),您可以传递一个带有 retries 值的对象作为第二个参数。
如果 delayRender() 调用在超时内未清除,则整个浏览器选项卡将被关闭,并且将从头开始重试帧。

重试 delayRender()
tsx
import { delayRender } from "remotion";
 
delayRender("Loading asset...", {
retries: 1, // default: 0
});
重试 delayRender()
tsx
import { delayRender } from "remotion";
 
delayRender("Loading asset...", {
retries: 1, // default: 0
});

<Img><Audio><Video><IFrame> 标签支持一个 delayRenderRetries 属性,用于控制这些组件进行的 delayRender() 调用的 retries 值。

修改超时时间v4.0.140

除了可以设置的全局超时时间,超时时间可以在每个 delayRender() 级别上进行修改。

修改 delayRender() 的超时时间
tsx
import { delayRender } from "remotion";
 
delayRender("Loading asset...", {
timeoutInMilliseconds: 7000,
});
修改 delayRender() 的超时时间
tsx
import { delayRender } from "remotion";
 
delayRender("Loading asset...", {
timeoutInMilliseconds: 7000,
});

<Img><Audio><Video><IFrame> 标签支持一个 delayRenderTimeoutInMilliseconds 属性,用于控制这些组件进行的 delayRender() 调用的 timeoutInMilliseconds 值。```

useBufferState().delayPlayback() 的区别

useBufferState() 是一个不同的 API,允许在 StudioPlayer 中暂停播放。

如果您正在加载数据,您可能希望在渲染过程中延迟组件的截图,并在预览期间启动缓冲状态,在这种情况下,您需要同时使用这两个 API。

同时使用 delayRender() 和 delayPlayback()
tsx
import React from "react";
import { useBufferState, delayRender, continueRender } from "remotion";
 
const MyComp: React.FC = () => {
const buffer = useBufferState();
const [handle] = React.useState(() => delayRender());
 
React.useEffect(() => {
const delayHandle = buffer.delayPlayback();
 
setTimeout(() => {
delayHandle.unblock();
continueRender(handle);
}, 5000);
 
return () => {
delayHandle.unblock();
};
}, []);
 
return <></>;
};
同时使用 delayRender() 和 delayPlayback()
tsx
import React from "react";
import { useBufferState, delayRender, continueRender } from "remotion";
 
const MyComp: React.FC = () => {
const buffer = useBufferState();
const [handle] = React.useState(() => delayRender());
 
React.useEffect(() => {
const delayHandle = buffer.delayPlayback();
 
setTimeout(() => {
delayHandle.unblock();
continueRender(handle);
}, 5000);
 
return () => {
delayHandle.unblock();
};
}, []);
 
return <></>;
};

另请参阅