[英]React context state updates are always one step behind
我已經閱讀了類似標題的問題,但它們並沒有解決我的問題。
我有一個 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>
)}
</>
);
}
視頻播放器.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>
);
}
視頻上下文.js :
import { createContext } from "react";
export default createContext({
video: {},
setVideo: () => {}
});
它在頁面加載時工作,但是當我的Link
組件更改videoHash
屬性時,新視頻會加載(我可以看到console.log()
API 調用)但它不會在視頻播放器中更新。
第二次單擊鏈接並更改videoHash
參數時,會顯示視頻,但它是針對上一個視頻的。
https://codesandbox.io/s/blazing-lake-k4i8n?file=/src/VideoPlayer.js
除非我遺漏了什么,否則我認為 VideoPlayer 可以作為一個沒有任何 state 鈎子的功能組件運行,這可以由 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: () => {}
});
我添加了一個超時,這樣你就可以看到加載部分也能正常工作。 讓我知道我是否缺少您需要做的事情。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.