React-player:无法播放映射数组中的选定项目
React-player: unable to play just selected item from mapped array
我在 nextjs-app 中使用 react-player 来显示通过 youtube-api 获取的视频。
一切正常,点击 playBtn 后模式打开,但播放器播放所有视频,而不仅仅是选定的视频。我真的不知道为什么,因为我将 videoId 设置为
url 的 RectPlayer 动态。有人能告诉我我做错了什么吗?
这是来源:
export default function Playlist({ videos }) {
const [open, setOpen] = useState(false);
const onOpenModal = () => setOpen(true);
const onCloseModal = () => setOpen(false);
const videoURL = "https://www.youtube.com/watch?v=";
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.contentDetails.videoPublishedAt) -
Number(new Date(a.contentDetails.videoPublishedAt))
)
)
return (
...
{sortedVids.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout="fill"
objectFit="cover"
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={onOpenModal}
>
<Image
src="/images/play.svg"
width="60"
height="60"
/>
</button>
<div>
<Modal
open={open}
onClose={onCloseModal}
center
classNames={{
overlay: "customOverlay",
modal: "customModal",
overlayAnimationIn: "customEnterOverlayAnimation",
overlayAnimationOut:
"customLeaveOverlayAnimation",
modalAnimationIn: "customEnterModalAnimation",
modalAnimationOut: "customLeaveModalAnimation",
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={
videoURL + `${vid.snippet.resourceId.videoId}`,
}
width="100%"
height="calc(100vh - 100px)"
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
);
}
更新:
我尝试使用这样的第二个状态:
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
{sortedVids
.filter((v) => v.snippet.title !== 'Private video')
.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout='fill'
objectFit='cover'
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={() => {
setModalData(vid.snippet.resourceId.videoId);
console.log(modalData);
setModalIsOpen(true);
}}
>
<Image src='/images/play.svg' width='60' height='60' />
</button>
<div>
<Modal
key={modalData}
open={modalIsOpen}
onClose={() => setModalIsOpen(false)}
center
classNames={{
overlay: 'customOverlay',
modal: 'customModal',
overlayAnimationIn: 'customEnterOverlayAnimation',
overlayAnimationOut: 'customLeaveOverlayAnimation',
modalAnimationIn: 'customEnterModalAnimation',
modalAnimationOut: 'customLeaveModalAnimation',
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={videoURL + `${modalData}`}
width='100%'
height='calc(100vh - 100px)'
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
但结果是一样的...
您的 onOpenModal
打开所有模型。最好的方法是将视频逻辑提取到它自己的组件中并像这样调用它们:
export default function Playlist({ videos }) {
const videoURL = "https://www.youtube.com/watch?v=";
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.contentDetails.videoPublishedAt) -
Number(new Date(a.contentDetails.videoPublishedAt))
)
)
return (
...
{sortedVids.map((vid, id) => {
return (<MagicVidComponent vid={vid}/>)
}
})
}
const MagicVidComponent = (vid) => {
const [open, setOpen] = useState(false);
const onOpenModal = () => setOpen(true);
const onCloseModal = () => setOpen(false);
return (
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout="fill"
objectFit="cover"
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={setIdToOpen(id)}
>
<Image
src="/images/play.svg"
width="60"
height="60"
/>
</button>
<div>
<Modal
open={idToOpen === id}
onClose={onCloseModal}
center
classNames={{
overlay: "customOverlay",
modal: "customModal",
overlayAnimationIn: "customEnterOverlayAnimation",
overlayAnimationOut:
"customLeaveOverlayAnimation",
modalAnimationIn: "customEnterModalAnimation",
modalAnimationOut: "customLeaveModalAnimation",
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={
videoURL + `${vid.snippet.resourceId.videoId}`,
}
width="100%"
height="calc(100vh - 100px)"
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
)
}
但是你可以快速而肮脏地做类似的事情:
export default function Playlist({ videos }) {
const [idToOpen, setIdToOpen] = useState();
const onCloseModal = () => setIdToOpen(undefined);
const videoURL = "https://www.youtube.com/watch?v=";
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.contentDetails.videoPublishedAt) -
Number(new Date(a.contentDetails.videoPublishedAt))
)
)
return (
...
{sortedVids.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout="fill"
objectFit="cover"
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={setIdToOpen(id)}
>
<Image
src="/images/play.svg"
width="60"
height="60"
/>
</button>
<div>
<Modal
open={idToOpen === id}
onClose={onCloseModal}
center
classNames={{
overlay: "customOverlay",
modal: "customModal",
overlayAnimationIn: "customEnterOverlayAnimation",
overlayAnimationOut:
"customLeaveOverlayAnimation",
modalAnimationIn: "customEnterModalAnimation",
modalAnimationOut: "customLeaveModalAnimation",
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={
videoURL + `${vid.snippet.resourceId.videoId}`,
}
width="100%"
height="calc(100vh - 100px)"
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
);
}
替换了地图函数之外的模式,它包含容器并传递了 modalDate onClick。此代码对我有用:
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
const videoURL = "https://www.youtube.com/watch?v=" + modalData;
return (
<>
...
{sortedVids
.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<button
className={styles.playBtn}
onClick={() => {
setModalData(vid.snippet.resourceId.videoId);
console.log(modalData);
setModalIsOpen(true);
}}
>
<Image src="/images/play.svg" width="60" height="60" />
</button>
</div>
</div>
);
})}
</div>
<div>
<Modal
open={modalIsOpen}
onClose={() => setModalIsOpen(false)}
center >
<ReactPlayer
playing={true}
url={videoURL}
config={{
youtube: {
playerVars: {
autoplay: 1,
controls: 1,
},
},
}}
/>
</Modal>
</div>
</div>
</>
);
我在 nextjs-app 中使用 react-player 来显示通过 youtube-api 获取的视频。 一切正常,点击 playBtn 后模式打开,但播放器播放所有视频,而不仅仅是选定的视频。我真的不知道为什么,因为我将 videoId 设置为 url 的 RectPlayer 动态。有人能告诉我我做错了什么吗? 这是来源:
export default function Playlist({ videos }) {
const [open, setOpen] = useState(false);
const onOpenModal = () => setOpen(true);
const onCloseModal = () => setOpen(false);
const videoURL = "https://www.youtube.com/watch?v=";
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.contentDetails.videoPublishedAt) -
Number(new Date(a.contentDetails.videoPublishedAt))
)
)
return (
...
{sortedVids.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout="fill"
objectFit="cover"
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={onOpenModal}
>
<Image
src="/images/play.svg"
width="60"
height="60"
/>
</button>
<div>
<Modal
open={open}
onClose={onCloseModal}
center
classNames={{
overlay: "customOverlay",
modal: "customModal",
overlayAnimationIn: "customEnterOverlayAnimation",
overlayAnimationOut:
"customLeaveOverlayAnimation",
modalAnimationIn: "customEnterModalAnimation",
modalAnimationOut: "customLeaveModalAnimation",
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={
videoURL + `${vid.snippet.resourceId.videoId}`,
}
width="100%"
height="calc(100vh - 100px)"
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
);
}
更新: 我尝试使用这样的第二个状态:
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
{sortedVids
.filter((v) => v.snippet.title !== 'Private video')
.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout='fill'
objectFit='cover'
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={() => {
setModalData(vid.snippet.resourceId.videoId);
console.log(modalData);
setModalIsOpen(true);
}}
>
<Image src='/images/play.svg' width='60' height='60' />
</button>
<div>
<Modal
key={modalData}
open={modalIsOpen}
onClose={() => setModalIsOpen(false)}
center
classNames={{
overlay: 'customOverlay',
modal: 'customModal',
overlayAnimationIn: 'customEnterOverlayAnimation',
overlayAnimationOut: 'customLeaveOverlayAnimation',
modalAnimationIn: 'customEnterModalAnimation',
modalAnimationOut: 'customLeaveModalAnimation',
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={videoURL + `${modalData}`}
width='100%'
height='calc(100vh - 100px)'
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
但结果是一样的...
您的 onOpenModal
打开所有模型。最好的方法是将视频逻辑提取到它自己的组件中并像这样调用它们:
export default function Playlist({ videos }) {
const videoURL = "https://www.youtube.com/watch?v=";
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.contentDetails.videoPublishedAt) -
Number(new Date(a.contentDetails.videoPublishedAt))
)
)
return (
...
{sortedVids.map((vid, id) => {
return (<MagicVidComponent vid={vid}/>)
}
})
}
const MagicVidComponent = (vid) => {
const [open, setOpen] = useState(false);
const onOpenModal = () => setOpen(true);
const onCloseModal = () => setOpen(false);
return (
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout="fill"
objectFit="cover"
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={setIdToOpen(id)}
>
<Image
src="/images/play.svg"
width="60"
height="60"
/>
</button>
<div>
<Modal
open={idToOpen === id}
onClose={onCloseModal}
center
classNames={{
overlay: "customOverlay",
modal: "customModal",
overlayAnimationIn: "customEnterOverlayAnimation",
overlayAnimationOut:
"customLeaveOverlayAnimation",
modalAnimationIn: "customEnterModalAnimation",
modalAnimationOut: "customLeaveModalAnimation",
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={
videoURL + `${vid.snippet.resourceId.videoId}`,
}
width="100%"
height="calc(100vh - 100px)"
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
)
}
但是你可以快速而肮脏地做类似的事情:
export default function Playlist({ videos }) {
const [idToOpen, setIdToOpen] = useState();
const onCloseModal = () => setIdToOpen(undefined);
const videoURL = "https://www.youtube.com/watch?v=";
const sortedVids = videos
.sort((a, b) =>
Number(
new Date(b.contentDetails.videoPublishedAt) -
Number(new Date(a.contentDetails.videoPublishedAt))
)
)
return (
...
{sortedVids.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<Image
className={styles.thumbnails}
src={vid.snippet.thumbnails.medium.url}
layout="fill"
objectFit="cover"
alt={vid.snippet.title}
/>
<button
className={styles.playBtn}
onClick={setIdToOpen(id)}
>
<Image
src="/images/play.svg"
width="60"
height="60"
/>
</button>
<div>
<Modal
open={idToOpen === id}
onClose={onCloseModal}
center
classNames={{
overlay: "customOverlay",
modal: "customModal",
overlayAnimationIn: "customEnterOverlayAnimation",
overlayAnimationOut:
"customLeaveOverlayAnimation",
modalAnimationIn: "customEnterModalAnimation",
modalAnimationOut: "customLeaveModalAnimation",
}}
animationDuration={800}
>
<ReactPlayer
playing={true}
url={
videoURL + `${vid.snippet.resourceId.videoId}`,
}
width="100%"
height="calc(100vh - 100px)"
/>
</Modal>
</div>
</div>
<div className={styles.details_container}>
<h3>{vid.snippet.title}</h3>
</div>
</div>
);
})}
);
}
替换了地图函数之外的模式,它包含容器并传递了 modalDate onClick。此代码对我有用:
const [modalIsOpen, setModalIsOpen] = useState(false);
const [modalData, setModalData] = useState(null);
const videoURL = "https://www.youtube.com/watch?v=" + modalData;
return (
<>
...
{sortedVids
.map((vid, id) => {
return (
<div className={styles.item_container} key={id}>
<div className={styles.clip_container}>
<button
className={styles.playBtn}
onClick={() => {
setModalData(vid.snippet.resourceId.videoId);
console.log(modalData);
setModalIsOpen(true);
}}
>
<Image src="/images/play.svg" width="60" height="60" />
</button>
</div>
</div>
);
})}
</div>
<div>
<Modal
open={modalIsOpen}
onClose={() => setModalIsOpen(false)}
center >
<ReactPlayer
playing={true}
url={videoURL}
config={{
youtube: {
playerVars: {
autoplay: 1,
controls: 1,
},
},
}}
/>
</Modal>
</div>
</div>
</>
);