簡體   English   中英

反應上下文 state 更新總是落后一步

[英]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 將更改

視頻播放器.js

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>
  );
}

Watch.js

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>
      )}
    </>
  );
}

VideoContext.js

import { createContext } from "react";

export default createContext({
  video: "",
  setVideo: () => {}
});

我添加了一個超時,這樣你就可以看到加載部分也能正常工作。 讓我知道我是否缺少您需要做的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM