当前位置: 首页 > 知识库问答 >
问题:

在React with React Hooks上使用动态导入视频

彭华皓
2023-03-14

我正在制作一种带有全屏视频背景的个人网站。我需要为不同的屏幕大小加载不同的视频。我正在使用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函数,根据窗口宽度动态加载视频,并向浏览器中的事件侦听器添加一个函数,以便在每次调整大小时重新加载视频:

  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);
    };
  }, []);

基于windows宽度动态加载视频的函数“loadVideo”是一个异步函数,因为我使用的是React提供的Dinamic导入语法,这是一个promise(我想这是最大的问题)。这是我的完整组件,“loadVideo”功能位于开头:

“/styles”文件是一个基于样式化组件库的组件,我用它来设置html的样式,这没关系(我想)。但是“视频”组件是HTML5中的视频标签。

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;

问题是背景视频没有播放。但是海报图像出现了,我不知道为什么只有海报图像起作用。我放了那个控制台。在返回之前记录,以尝试了解发生了什么,以下是记录的内容:

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”第一次给我的状态的属性分配了一个空值,就在这之后,“use效应”调用了“loadVideo”函数。

我第一次尝试导入并分配视频到“useState”,正常工作!但是,我不能有一个视频开始与"useState",因为我需要知道屏幕大小之前,并下载适当的视频。

我还尝试使用"loadVideo"函数和"useState",像这样:

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

但是,它不起作用,因为“loadVideo”是异步的。

有没有人对这个问题有什么解决办法,或者对我想做的事情有更好的方法

谢谢你!

共有1个答案

高弘光
2023-03-14

import()没有加载视频,它只是获取URL。你可以同步完成。

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

if (width>1280) {
    src = videoSrc720;
} ...
 类似资料:
  • 问题内容: 我正在尝试从其他目录动态导入模块。我正在从这个问题中得到答案。我在名为foo的目录中有一个名为bar的模块。主脚本将在foo的父目录中运行。 这是我到目前为止在测试脚本中拥有的代码(正在foo的父目录中运行) 和bar.py的代码 但是当我运行test.py时,出现此错误: 问题答案: 需要导入模块的路径名+文件名,您应该将源代码更改为以下代码之一:

  • 我们在前面章节中介绍的导出和导入语句称为“静态”导入。语法非常简单且严格。 首先,我们不能动态生成 import 的任何参数。 模块路径必须是原始类型字符串,不能是函数调用,下面这样的 import 行不通: import ... from getModuleName(); // Error, only from "string" is allowed 其次,我们无法根据条件或者在运行时导入: i

  • Examples With Dynamic Import ext.js 支持 JavaScript 的 TC39 提议dynamic import proposal。你可以动态导入 JavaScript 模块(如 React 组件)。 动态导入相当于把代码分成各个块管理。Next.js 服务端动态导入功能,你可以做很多炫酷事情。 下面介绍一些动态导入方式: 1. 基础支持 (同样支持 SSR) i

  • 尽管有些系统管理员喜欢将他们自己与其它使用成堆的老旧打印机的办公室相隔绝, 但是我们还是需要随时与其他部门交换信息。 例如,你可能需要插入数据到你的 Puppet 配置清单,这些数据是从外部数据源派生出来的。 generate 函数在这方面相当有用。 准备工作 在 Puppetmaster 上使用如下代码创建脚本 /usr/local/bin/latest-puppet.rb: #!/usr/bi

  • 问题内容: 因此,这是我当前通过ES6导入Webpack中的图像和图标的工作流程: 这变得很快。这就是我想要的: 我觉得必须有某种方法可以动态地从特定目录中导入所有文件(不带扩展名),然后根据需要使用这些文件。 任何人都看过此事,或者对最佳解决方案有任何想法? 更新: 使用选择的答案,我能够做到这一点: 问题答案: 我觉得必须有某种方法可以动态地从特定目录中导入所有文件(不带扩展名),然后根据需要

  • 我试图找到一种方法来动态导入继承一些标准样式的svg图标。我没有看到其他人写这个...所以我想我走错了路。 我尝试过在样式化的组件中创建一个SVG包装器,但这给了我一个svg的巢 SVG图标代码 我的图标代码 导入正在工作并显示,但我希望将组件作为样式化组件,这将使我能够使用道具设置主题并动态更改SVG样式。