我不知道如何防止
playerRef
在 clipLink
更改时重新加载。
当我在开发模式下工作时(
npm run dev
),我可以切换视频而无需重新加载playerRef
。但是,当我在制作模式下工作时(npm run build && npm start
),我无法在不重新加载的情况下切换视频playerRef
。
请假设父组件中有一个按钮,单击时会更改
clipLink
(为简单起见,我从此处的代码中将其删除)
这是父组件
import { useRef } from "react";
import { YouTubePlayer } from 'react-youtube';
import ChildPage from "@/components/ChildPage";
const ParentPage = () => {
const playerRef = useRef<YouTubePlayer | null>(null);
return (
<>
<ChildPage
clipLink={clipLink}
playerRef={playerRef}
/>
</>
);
};
export default ParentPage;
这是子组件
import { useEffect } from "react";
import YouTube, { YouTubeProps } from 'react-youtube';
const ChildPage = ({ clipLink, playerRef }) => {
const onPlayerReady: YouTubeProps['onReady'] = (event) => {
playerRef.current = event.target;
event.target.playVideo();
event.target.setVolume(30);
};
const onPlayerStateChange: YouTubeProps['onStateChange'] = (event) => {
const playerState = event.data;
switch (playerState) {
case 0:
event.target.playVideo();
break;
default:
console.log('Player state changed to:', playerState);
}
};
const opts: YouTubeProps['opts'] = {
playerVars: {
autoplay: 1,
controls: 1,
fs: 0,
modestbranding: 1,
rel: 0,
iv_load_policy: 3,
},
};
useEffect(() => {
if (clipLink && playerRef.current) {
try {
playerRef.current.loadVideoById(clipLink);
playerRef.current.playVideo();
playerRef.current.setVolume(30);
} catch (error) {
console.error('Error loading video -', error);
}
}
}, [clipLink]);
return (
<>
<YouTube
videoId={clipLink}
opts={opts}
onReady={onPlayerReady}
onStateChange={onPlayerStateChange}
/>
</>
);
};
export default ChildPage;
如您所见,在子组件中,我有
playerRef.current.loadVideoById(clipLink);
。
我认为这段代码会在不重新加载的情况下更改
playerRef
的视频,并且它在开发模式下确实按预期工作(npm run dev
)。
但是,在生产模式下(
npm run build && npm start
),它并不能按预期工作...
您遇到的问题源于 React 如何处理组件重新渲染和 YouTube 库。当
clipLink
发生变化时,React 会在生产模式下卸载并重新安装 YouTube 播放器,从而导致 playerRef
重置。在开发模式下,React 的热重载行为可能会抑制某些重新安装行为,这可以解释这种差异。
要解决此问题,您必须确保 YouTube 播放器保持安装状态,即使
clipLink
发生变化也是如此。您可以使用播放器的 loadVideoById 方法更新正在播放的视频,而不是卸载和重新安装播放器。
import { useEffect } from "react";
import YouTube, { YouTubeProps } from 'react-youtube';
const ChildPage = ({ clipLink, playerRef }) => {
const onPlayerReady: YouTubeProps['onReady'] = (event) => {
playerRef.current = event.target;
event.target.playVideo();
event.target.setVolume(30);
};
const onPlayerStateChange: YouTubeProps['onStateChange'] = (event) => {
const playerState = event.data;
switch (playerState) {
case 0:
event.target.playVideo();
break;
default:
console.log('Player state changed to:', playerState);
}
};
const opts: YouTubeProps['opts'] = {
playerVars: {
autoplay: 1,
controls: 1,
fs: 0,
modestbranding: 1,
rel: 0,
iv_load_policy: 3,
},
};
// UseEffect to update the video when clipLink changes
useEffect(() => {
if (playerRef.current && clipLink) {
const videoId = new URLSearchParams(new URL(clipLink).search).get('v');
if (videoId) {
playerRef.current.loadVideoById(videoId);
}
}
}, [clipLink, playerRef]);
return (
<YouTube
videoId={new URLSearchParams(new URL(clipLink).search).get('v') || ""}
opts={opts}
onReady={onPlayerReady}
onStateChange={onPlayerStateChange}
/>
);
};
export default ChildPage;