Использование динамического импорта c с видео в React с React Hooks - PullRequest
1 голос
/ 20 апреля 2020

Я создаю своего рода персональный сайт с полноэкранным видео в фоновом режиме. И Мне нужно загрузить другое видео для экрана разных размеров . Я использую React и создаю компонент на основе React Hooks.

Это моя версия зависимостей:

    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.4.1",

Внутри моего компонента "VideoBackground" я создал состояние с помощью useState, где я будет хранить источник видео и источник изображения плаката, например:

  const [video, setVideo] = useState({
    poster: null,
    src: null,
  });

И я использую ловушку useEffect для работы в качестве функции componentDidMount, где я собираюсь загружать видео динамически на основе на ширину windows и добавьте функцию в прослушиватели событий в браузере для перезагрузки видео каждый раз, когда происходит изменение размера:

  useEffect(() => {
    async function handleResize() {
      setVideo(await loadVideo());
    }

    handleResize();

    window.addEventListener("resize", handleResize);
    window.addEventListener("orientationchange", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
      window.removeEventListener("orientationchange", handleResize);
    };
  }, []);

Функция «loadVideo», которая загружает видео динамически на основе windows width - это асинхронная c функция, потому что я использую синтаксис Dinami c Import, предоставленный React, который является Promise (это самая большая проблема, которую я предполагаю). Это мой полный компонент, функция «loadVideo» находится в начале:

Файл «./styles» - это компонент, основанный на библиотеке стилей с компонентами, я использую его для стилизации моего html, это не имеет значения (наверное). Но компонент «Видео» - это тег видео из html 5.

import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";

import { Video, Overlay, Content } from "./styles";

const VideoBackground = ({ children }) => {
  /*
   * Media query of the resource's intended media; this should be used only in a <picture> element
   *
   * Extra large devices (large laptops and desktops, 1200px and up)
   * Large devices (laptops/desktops, 992px and up)
   * Medium devices (landscape tablets, 768px and up)
   * Small devices (portrait tablets and large phones, 600px and up)
   * Extra small devices (phones, 600px and down)
   */
  async function loadVideo() {
    const { width } = getWindowDimensions();

    let posterPromise;
    let srcPromise;

    if (width > 1280) {
      posterPromise = import("../../assets/images/code720.jpg");
      srcPromise = import("../../assets/videos/code720.mp4");
    } else if (width > 720) {
      posterPromise = import("../../assets/images/code480.jpg");
      srcPromise = import("../../assets/videos/code480.mp4");
    } else if (width > 480) {
      posterPromise = import("../../assets/images/code320.jpg");
      srcPromise = import("../../assets/videos/code320.mp4");
    } else {
      posterPromise = import("../../assets/images/code240.jpg");
      srcPromise = import("../../assets/videos/code240.mp4");
    }

    const [{ default: poster }, { default: src }] = await Promise.all([
      posterPromise,
      srcPromise,
    ]);

    return {
      poster,
      src,
    };
  }

  /*
   * It returns the width of a window's content area
   */
  function getWindowDimensions() {
    const { innerWidth: width } = window;

    return {
      width,
    };
  }

  const [video, setVideo] = useState({
    poster: null,
    src: null,
  });

  useEffect(() => {
    async function handleResize() {
      setVideo(await loadVideo());
    }

    handleResize();

    window.addEventListener("resize", handleResize);
    window.addEventListener("orientationchange", handleResize);

    return () => {
      window.removeEventListener("resize", handleResize);
      window.removeEventListener("orientationchange", handleResize);
    };
  }, []);

  console.log("BEFORE RETURN", video);

  return (
    <>
      <Video playsInline autoPlay muted loop poster={video.poster}>
        <source src={video.src} type="video/mp4" />
      </Video>
      <Overlay />
      <Content>{children}</Content>
    </>
  );
};

VideoBackground.propTypes = {
  children: PropTypes.node.isRequired,
};

export default VideoBackground;

Проблема в том, что фоновое видео не воспроизводится. Но изображение плаката появляется , и я не знаю, почему работает только изображение плаката. Я помещаю этот console.log перед возвратом, чтобы попытаться выяснить, что происходит, и вот что записывается:

BEFORE RETURN {poster: null, src: null}
BEFORE RETURN {poster: null, src: null}
BEFORE RETURN {poster: "/static/media/code720.e66bf519.jpg", src: "/static/media/code720.83f62f35.mp4"}
BEFORE RETURN {poster: "/static/media/code720.e66bf519.jpg", src: "/static/media/code720.83f62f35.mp4"}

Как видите, видео и изображения загружаются нормально ( Но через некоторое время). Я думаю, что проблема в том, что «useState» присваивает нулевое значение свойствам моего состояния в первый раз , и сразу после этого «useEffect» вызывает функцию «loadVideo».

Я впервые попытался импортировать и назначить видео для «useState» и нормально работает! Однако у меня не получается запустить видео с «useState», потому что мне нужно знать размер экрана перед загрузкой соответствующего видео.

Я также пытался использовать функцию «loadVideo» с «useState», например:

const [video, setVideo] = useState(loadVideo());

Но это не работает, потому что «loadVideo» isyn c.

Есть ли у кого-нибудь решение этой проблемы или лучший способ для того, что я хочу сделать?

Спасибо!

1 Ответ

0 голосов
/ 20 апреля 2020

import() не загружает видео, оно просто получает URL. Вы можете сделать это синхронно.

import videoSrc720 from "../../assets/videos/code720.mp4";

if (width>1280) {
    src = videoSrc720;
} ...
...