我读过类似标题的问题,但它们没有解决我的问题。
我有一个 API 调用,其结果需要在多个组件之间共享。父组件进行调用,React 的上下文用于在子组件之间共享它:
MainPage.js:
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { VideoPlayer } from "../components/VideoPlayer";
import VideoContext from "../components/VideoContext";
export default function Watch() {
const [video, setVideo] = useState({});
const { videoHash } = useParams();
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(true);
getVideo();
}, [videoHash]);
const getVideo = async () => {
if(videoHash) {
const res = await getVideoFromApi();
setIsLoading(false);
// The first time this runs nothing happens, the video can't be played
// The second time it runs (i.e. when the URL/videoHash changes) it updates
// but it shows the video from the first run
setVideo(res.video);
}
};
return (
<>
{isLoading ? (
<div>Loading...</div>
) : (
<VideoContext.Provider value={{ video, setVideo }}>
<VideoPlayer videoHash={videoHash} />
</VideoContext.Provider>
)}
</>
);
}
VideoPlayer.js:
import React, { useState, useEffect, useContext } from "react";
import VideoContext from "./VideoContext";
import styles from "./VideoPlayer.module.css";
export function VideoPlayer({ videoHash }) {
const { video, setVideo } = useContext(VideoContext);
const [forceRender, setforceRender] = useState(true);
useEffect(() => {
// I tried adding this to no effect
setforceRender(!forceRender);
}, [videoHash]);
return (
<video controls className={styles["video-player"]}>
<source src={video.VideoUrl} type="video/mp4" />
Sorry, your browser does not support embedded videos.
</video>
);
}
VideoContext.js:
import { createContext } from "react";
export default createContext({
video: {},
setVideo: () => {}
});
它在页面加载时工作,但是当我的 Link
组件更改 videoHash
属性时,新视频会加载(我可以在 console.log()
API 调用时看到)但它没有在视频播放器中更新。
第二次点击链接并更改 videoHash
参数时,视频会显示,但它是针对上一个视频的。
答案 0 :(得分:1)
https://codesandbox.io/s/blazing-lake-k4i8n?file=/src/VideoPlayer.js
除非我遗漏了一些东西,否则我认为 VideoPlayer 只是作为一个没有任何状态钩子的功能组件可以正常工作,可以由 Watch 处理。当您单击指向将指向观看的另一条路线的链接时,videoHash 将发生变化
import React from "react";
import { Link } from "react-router-dom";
export function VideoPlayer({ videoHash }) {
// const { video, setVideo } = useContext(VideoContext);
// const [forceRender, setforceRender] = useState(true);
// useEffect(() => {
// // I tried adding this to no effect
// setforceRender(!forceRender);
// }, [videoHash]);
// console.log(video);
// Am I missi
return (
<div>
Am I missing something or could you just use your videoHash: {videoHash},
here?
<Link to="/watch/a">Previous</Link>
<Link to="/watch/c">Next</Link>
</div>
);
}
import React, { useState, useEffect, useCallback } from "react";
import { useParams } from "react-router-dom";
import { VideoPlayer } from "./VideoPlayer";
import VideoContext from "./VideoContext";
export default function Watch() {
const [video, setVideo] = useState({});
const { videoHash } = useParams();
const [isLoading, setIsLoading] = useState(true);
const getVideo = useCallback(async () => {
if (videoHash) {
const res = await getVideoFromApi();
setTimeout(() => {
setIsLoading(false);
setVideo(res);
}, 1000);
}
}, [videoHash]);
useEffect(() => {
setIsLoading(true);
getVideo();
}, [getVideo]);
const getVideoFromApi = async () => {
const videoArray = ["A", "B", "C"];
const randomItem =
videoArray[Math.floor(Math.random() * videoArray.length)];
return Promise.resolve(randomItem);
};
return (
<>
{isLoading ? (
<div>Loading...</div>
) : (
<VideoContext.Provider value={{ video, setVideo }}>
<VideoPlayer videoHash={videoHash} />
</VideoContext.Provider>
)}
</>
);
}
import { createContext } from "react";
export default createContext({
video: "",
setVideo: () => {}
});
我添加了一个超时,以便您可以看到加载部分也能正常工作。如果我遗漏了您需要做的事情,请告诉我。