我想滚动到下一个视频,比如YouTube短视频或者TikTok视频,滚动的时候想把URL改成当前显示视频的id,比如"https://example.com/{id}"
。
我可以用下面的代码实现它,但是视频变白了一会儿,可能是因为URL被navigate()
更改了。
我该怎么补救呢?
interface Video {
id: string;
videoUrl: string;
}
function Videos() {
const [videos, setVideos] = useState<Video[]>([]);
const params = useParams();
const navigate = useNavigate();
const refs = useRef<RefObject<HTMLDivElement>[]>([]);
const observer = new IntersectionObserver(entries => {
entries.forEach((entry) => {
const video = entry.target.querySelector("video") as HTMLVideoElement;
if (entry.isIntersecting) {
if (params.id !== id) navigate(id);
video.play();
} else {
video.pause();
}
});
}, { threshold: 0.5 });
useEffect(() => {
refs.current.forEach((ref) => {
if (ref.current) {
observer.observe(ref.current)
}
})
return () => {
refs.current.forEach((ref) => {
if (ref.current) {
observer.unobserve(ref.current)
}
})
}
});
const fetchVideos = async (): Promise<Video[]> => {
// ...
};
useEffect(() => {
fetchVideos().then(videos => {
videos.forEach((v, i) => refs.current[i] = createRef<HTMLDivElement>());
setVideos(videos);
if (!params.id) navigate(contents[0].id);
}).catch(error => {
alert("error");
});
}, []);
const Content = forwardRef(({ video }: { video: Video }, ref) => {
const videoRef = ref as MutableRefObject<HTMLDivElement>;
return (
<>
<div ref={videoRef}>
<video src={video.videoUrl} playsInline muted></video>
<input type="hidden" name="contentId" value={video.id} />
</div>
</>
);
});
return (
<div className="Videos">
{videos.map((v, i) => <Content key={v.id} ref={refs.current[i]} video={v} />)}
</div>
);
}
export default Videos;
CSS
.Videos {
scroll-snap-type: y mandatory;
overflow: auto;
height: 100vh;
> * {
scroll-snap-align: start;
}
}
video {
height: 100vh;
}
1条答案
按热度按时间rm5edbpk1#
我看到的代码中唯一明显的问题是
Content
组件是在另一个React组件中声明的。每次Videos
组件重新呈现时,无论出于什么原因,Content
组件都会重新声明。这意味着Content
组件的任何"示例"都将被卸载,并安装新的"示例"。单独声明React组件,使其成为稳定引用。