資料擷取
在 Remotion 影片中使用外部 API 資料與動態內容。
兩種資料擷取時機
在 Remotion 中取得外部資料有兩種方式,對應兩個不同的時機:
| 方式 | 時機 | 適用場景 |
|---|---|---|
calculateMetadata | 渲染前(決定影片規格時) | 影片長度、解析度需要根據資料決定 |
delayRender / continueRender | 渲染中(元件 mount 時) | 載入圖片、字型、API 資料 |
方式一:calculateMetadata
在渲染開始前擷取資料,適合需要根據資料決定影片規格的場景:
import { CalculateMetadataFunction } from "remotion";
interface VideoProps {
apiUrl: string;
data?: { items: string[]; title: string };
}
export const calculateMetadata: CalculateMetadataFunction<
VideoProps
> = async ({ props }) => {
// 在渲染前呼叫 API
const response = await fetch(props.apiUrl);
const data = await response.json();
return {
// 根據資料量決定影片長度
durationInFrames: data.items.length * 90,
// 把資料傳入 Props
props: {
...props,
data,
},
};
};calculateMetadata 的回傳值可以覆蓋 durationInFrames、fps、width、height,也可以修改傳給元件的 props。
在 Composition 中使用
<Composition
id="DataVideo"
component={DataVideo}
calculateMetadata={calculateMetadata}
defaultProps={{
apiUrl: "https://api.example.com/data",
}}
/>方式二:delayRender / continueRender
在元件內部擷取資料。Remotion 預設會立刻開始截圖每一幀,但有時你需要等資料載入完成。delayRender() 告訴 Remotion「先等一下」,continueRender() 告訴它「好了,可以開始了」:
import { useCallback, useEffect, useState } from "react";
import { delayRender, continueRender, AbsoluteFill } from "remotion";
export const DataDrivenScene: React.FC = () => {
const [data, setData] = useState<string[] | null>(null);
const [handle] = useState(() => delayRender("正在載入資料..."));
const fetchData = useCallback(async () => {
try {
const response = await fetch("https://api.example.com/items");
const json = await response.json();
setData(json.items);
continueRender(handle);
} catch (err) {
// 錯誤處理也必須呼叫 continueRender,否則渲染會永遠卡住
console.error(err);
continueRender(handle);
}
}, [handle]);
useEffect(() => {
fetchData();
}, [fetchData]);
if (!data) {
return null;
}
return (
<AbsoluteFill style={{ backgroundColor: "#0f0f1a" }}>
{data.map((item, i) => (
<div key={i} style={{ color: "white", fontSize: 36 }}>
{item}
</div>
))}
</AbsoluteFill>
);
};重要規則
- 一定要呼叫
continueRender()— 不管成功或失敗,都必須呼叫,否則渲染會無限等待直到超時。 delayRender()必須在元件第一次 render 時呼叫 — 不能放在useEffect裡,要放在useState的初始值中。- 有超時限制 — 預設 30 秒。如果資料載入超過這個時間,渲染會失敗。
載入圖片
載入遠端圖片也是一種資料擷取。用 <Img> 元件(注意大寫 I)會自動處理 delayRender:
import { Img } from "remotion";
export const ImageScene: React.FC<{ imageUrl: string }> = ({ imageUrl }) => {
return (
<AbsoluteFill>
<Img src={imageUrl} style={{ width: "100%" }} />
</AbsoluteFill>
);
};<Img> 內部會自動呼叫 delayRender(),等圖片載入完成後才讓 Remotion 繼續渲染。如果你用原生 <img> 標籤,圖片可能還沒載入就被截圖了。
載入字型
Google Fonts 或自訂字型也需要等待載入:
import { useState } from "react";
import { delayRender, continueRender } from "remotion";
const waitForFont = delayRender("正在載入字型...");
const font = new FontFace(
"MyCustomFont",
"url(https://example.com/font.woff2)"
);
font
.load()
.then(() => {
document.fonts.add(font);
continueRender(waitForFont);
})
.catch((err) => {
console.error("字型載入失敗", err);
continueRender(waitForFont);
});選擇哪種方式?
需要根據資料決定影片長度或解析度?
→ 用 calculateMetadata
只是在元件中顯示外部資料?
→ 用 delayRender / continueRender
載入圖片?
→ 用 Remotion 的 <Img> 元件(自動處理)
載入字型?
→ 用 delayRender + FontFace API
小結
calculateMetadata— 渲染前取得資料,可以動態決定影片規格和 PropsdelayRender/continueRender— 渲染中暫停等待資料,記得一定要呼叫continueRender()<Img>— Remotion 的圖片元件,自動等待載入完成- 不管用哪種方式,都要處理錯誤情況,避免渲染無限卡住