Компонент React не выполняет повторную визуализацию, если имеется только одно обновление состояния - PullRequest
0 голосов
/ 01 февраля 2020

У меня есть 2 компонента -> a) VideoJSPlayer и b) VideosPage.

Как следует из названия, VideoJsPlayer имеет часть проигрывателя видео (с использованием видео js), а 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) VideosPage

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, который рендерит компонент VideosPage, я не вижу видео. Я предполагаю, что состояние (videoJsOptions) еще не обновлено в VideosPage и, следовательно, я не вижу видео. Я вижу консольный журнал - "test", хотя.

Когда я изменяю код 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, который отображает компонент VideosPage, я вижу видео.

Мое предположение - в первом случае обновление состояния ставится в очередь и никогда не происходит. Потому что, если бы это произошло, он должен был повторно визуализировать компонент, и я должен был увидеть мое видео.

Я также пытался обновить useEffect в VideoJSPlayer, чтобы запускать каждый раз, когда изменения реквизита, но это не помогло.

Есть идеи по этому поводу?

Спасибо за ваше время.

Вот песочница: codesandbox

1 Ответ

0 голосов
/ 01 февраля 2020

У вас есть некоторые ошибки:

  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" />
 )
}
Вам не нужно снова использовать useEffect в своем компоненте VideosPage, так как он уже использовался в вашем VideoJsPlayer компоненте. Первоначальные параметры необходимо установить непосредственно в state или вне функции, например:
const initialOptions = {
 // ...
}

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

Вот рабочий пример codeSandbox на основе вашего кода.

...