Skip to main content

显示当前时间

在应用程序中呈现<Player>时,必须特别考虑防止应用程序或<Player>因时间更改而不断重新渲染。

这就是为什么useCurrentFrame()钩子在组合之外不起作用。

warning

不要将此钩子放入呈现<Player>的同一组件中,否则您将看到不断重新渲染。相反,将其放入呈现Player的组件旁边的组件中。

与Player时间同步的组件

如果要显示与播放器时间同步的组件,例如时间轴组件的光标或自定义时间显示,可以使用以下钩子:

use-current-player-frame.ts
tsx
import { CallbackListener, PlayerRef } from "@remotion/player";
import { useCallback, useSyncExternalStore } from "react";
 
export const useCurrentPlayerFrame = (ref: React.RefObject<PlayerRef>) => {
const subscribe = useCallback(
(onStoreChange: () => void) => {
const { current } = ref;
if (!current) {
return () => undefined;
}
const updater: CallbackListener<"frameupdate"> = ({ detail }) => {
onStoreChange();
};
current.addEventListener("frameupdate", updater);
return () => {
current.removeEventListener("frameupdate", updater);
};
},
[ref]
);
 
const data = useSyncExternalStore<number>(
subscribe,
() => ref.current?.getCurrentFrame() ?? 0,
() => 0
);
 
return data;
};
use-current-player-frame.ts
tsx
import { CallbackListener, PlayerRef } from "@remotion/player";
import { useCallback, useSyncExternalStore } from "react";
 
export const useCurrentPlayerFrame = (ref: React.RefObject<PlayerRef>) => {
const subscribe = useCallback(
(onStoreChange: () => void) => {
const { current } = ref;
if (!current) {
return () => undefined;
}
const updater: CallbackListener<"frameupdate"> = ({ detail }) => {
onStoreChange();
};
current.addEventListener("frameupdate", updater);
return () => {
current.removeEventListener("frameupdate", updater);
};
},
[ref]
);
 
const data = useSyncExternalStore<number>(
subscribe,
() => ref.current?.getCurrentFrame() ?? 0,
() => 0
);
 
return data;
};

使用示例

将React Player添加到引用中并将其传递给另一个组件:

tsx
import { Player, PlayerRef } from "@remotion/player";
import { useRef } from "react";
import { MyVideo } from "./remotion/MyVideo";
import { TimeDisplay } from "./remotion/TimeDisplay";
 
export const App: React.FC = () => {
const playerRef = useRef<PlayerRef>(null);
 
return (
<>
<Player
ref={playerRef}
component={MyVideo}
durationInFrames={120}
compositionWidth={1920}
compositionHeight={1080}
fps={30}
/>
<TimeDisplay playerRef={playerRef} />
</>
);
};
tsx
import { Player, PlayerRef } from "@remotion/player";
import { useRef } from "react";
import { MyVideo } from "./remotion/MyVideo";
import { TimeDisplay } from "./remotion/TimeDisplay";
 
export const App: React.FC = () => {
const playerRef = useRef<PlayerRef>(null);
 
return (
<>
<Player
ref={playerRef}
component={MyVideo}
durationInFrames={120}
compositionWidth={1920}
compositionHeight={1080}
fps={30}
/>
<TimeDisplay playerRef={playerRef} />
</>
);
};

这是组件如何访问当前时间的方式:

TimeDisplay.tsx
tsx
import React from "react";
import { PlayerRef } from "@remotion/player";
import { useCurrentPlayerFrame } from "./use-current-player-frame";
 
export const TimeDisplay: React.FC<{
playerRef: React.RefObject<PlayerRef>;
}> = ({ playerRef }) => {
const frame = useCurrentPlayerFrame(playerRef);
 
return <div>current frame: {frame}</div>;
};
TimeDisplay.tsx
tsx
import React from "react";
import { PlayerRef } from "@remotion/player";
import { useCurrentPlayerFrame } from "./use-current-player-frame";
 
export const TimeDisplay: React.FC<{
playerRef: React.RefObject<PlayerRef>;
}> = ({ playerRef }) => {
const frame = useCurrentPlayerFrame(playerRef);
 
return <div>current frame: {frame}</div>;
};

这种方法是高效的,因为只有视频本身和依赖于时间的组件会重新渲染,而<App>组件不会重新渲染。