如果只有一个状态更新,React组件不会重新渲染

时间:2020-02-01 07:54:35

标签: reactjs react-hooks video.js react-state-management

我有2个组件-> a)VideoJSPlayer和b)VideosPage。

顾名思义,VideoJsPlayer具有视频播放器部分(使用videojs),而VideosPage使用VideoJsPlayer组件显示视频。

每个组件的代码为:

a)VideoJsPlayer

import React, { useEffect } from "react";
import videojs from "video.js";

const VideoJsPlayer = props => {
  let player = null;
  let videoNode = null;

  // Effect for first render only.
  useEffect(() => {
    player = videojs(videoNode, props, function onPlayerReady() {
      console.log("onPlayerReady");
    });
    return function cleanup() {
      if (player) {
        player.dispose();
      }
    };
  }, []);

  return (
    <div>
      <div data-vjs-player>
        <video ref={node => (videoNode = node)} className="video-js"></video>
      </div>
    </div>
  );
};

export default VideoJsPlayer;

b)视频页面

import React, { useState, useEffect } from "react";
import videojs from "video.js";
import VideoJsPlayer from "../../components/VideoJsPlayer";

const VideosPage = props => {
  const [videoJsOptions, setVideoJsOptions] = useState({});

  // Effect for first render only.
  useEffect(() => {
    let videoJsOptionsTest = {
      autoplay: false,
      controls: true,
      sources: [
        {
          src: "/my-video.mp4",
          type: "video/mp4"
        }
      ]
    };

    console.log("test");

    setVideoJsOptions(videoJsOptionsTest);

    // Cleanup on unmount.
    return function cleanup() {};
  }, []);

  return (
    <React.Fragment>
      <VideoJsPlayer {...videoJsOptions} />
    </React.Fragment>
  );
};

export default VideosPage;

当我检查呈现“视频页面”组件的URL时,看不到任何视频。我假设状态(videoJsOptions)尚未在VideosPage中更新,因此看不到视频。我可以看到控制台日志-不过是“测试”。

当我将VideosPage的代码更改为:

import React, { useState, useEffect } from "react";
import videojs from "video.js";
import VideoJsPlayer from "../../components/VideoJsPlayer";

const VideosPage = props => {
  const [videoJsOptions, setVideoJsOptions] = useState({
    autoplay: false,
    controls: true,
    sources: [
      {
        src: "/my-video.mp4",
        type: "video/mp4"
      }
    ]
  });

  // Effect for first render only.
  useEffect(() => {
    /*
    let videoJsOptionsTest = {
      autoplay: false,
      controls: true,
      sources: [
        {
          src: "/my-video.mp4",
          type: "video/mp4"
        }
      ]
    };

    console.log("test");

    setVideoJsOptions(videoJsOptionsTest);
    */

    // Cleanup on unmount.
    return function cleanup() {};
  }, []);

  return (
    <React.Fragment>
      <VideoJsPlayer {...videoJsOptions} />
    </React.Fragment>
  );
};

export default VideosPage;

现在,当我检查呈现“视频页面”组件的URL时,我会看到视频。

我的假设是-在第一种情况下,状态更新已排队并且从未发生。因为如果发生的话,它应该重新渲染了该组件,我也应该看过我的视频。

我还尝试过在VideoJSPlayer中更新useEffect以在每次更改道具时运行,但这没有帮助。

对此有何见解?

谢谢您的时间。

这是一个沙箱:codesandbox

1 个答案:

答案 0 :(得分:0)

您有一些错误:

  1. 不能这样使用videoNode,因为Video.js使用Ref,并且由于您使用的是React钩子,因此您需要使用useRef
import React, { useRef, useEffect } from "react"

const VideoJsPlayer = props => {
  const videoRef = useRef(null)

  useEffect(() => {
    //...
    videojs(
      videoRef.current,
      props,
      function onPlayerReady() {
        console.log("onPlayerReady")
      }
    )
   //...
  }, [])

 return (
   <video ref={videoRef} className="video-js" />
 )
}
  1. 您无需在useEffect组件中再次使用VideosPage,因为它已在VideoJsPlayer组件中使用。您的初始选项需要直接在state或函数外部进行设置,如下所示:
const initialOptions = {
 // ...
}

const VideosPage = () => {
  return <VideoJsPlayer {...initialOptions} />
}

这是一个基于您的代码的有效codeSandbox示例。