首页 > 解决方案 > 导入的动态组件卡在加载阶段:下一个 js

问题描述

我是下一个 js 的新手。在我的项目中,我需要显示 youtube 视频。我有一个 api,它为我提供了要显示其元详细信息的视频 ID。我想为每个视频创建动态页面。我正在使用 react-player 作为播放器。

这是我的代码

[videoId].tsx

import Head from 'next/head';
import { useRouter } from 'next/router'
import Layout from '../../components/layout';
import { IVideoItem } from '../../models/videos.model';
import VideoContainer from '../../components/videos-page/video-container';
import { getVideosPaths, getVideosPageTitle, getVideosPageDescription, getVideosData  } from '../../services/videos-page.services';

export default function VideoPage({videoInfo} :IVideosPageProp) {
    const router = useRouter()

  if (router.isFallback) {
    return <div>Loading...</div>
  }
  return(
    <>
        <Head>
            <meta name="viewport" content="width=device-width, initial-scale=1" />
            <meta charSet="utf-8" />
            <title>{getVideosPageTitle(videoInfo)}</title>
            <meta name="description" content={getVideosPageDescription(videoInfo)} />
            <meta property="og:title" content={getVideosPageTitle(videoInfo)} key="ogtitle" />
            <meta property="og:description" content={getVideosPageDescription(videoInfo)} key="ogdesc" />

        </Head>
        <VideoContainer data={videoInfo} />
    </>
  )
}


export async function getStaticPaths() {
    const paths = await getVideosPaths()
    //console.log('paths: ',paths);
    return {
      paths,
      fallback: false
    }
  }

  export async function getStaticProps({ params }:IVideosPageStaticProp) {
    const {videoId} = params;
    const videoInfo = await getVideosData(videoId)
    return {
      props: {
        videoInfo
      }
    }
  }

interface IVideosPageProp {
    videoInfo: IVideoItem
}

interface IVideosPageStaticPropParams {
    videoId: string
}

interface IVideosPageStaticProp {
    params: IVideosPageStaticPropParams
}

视频容器.tsx

import { Row, Col } from 'react-bootstrap'
import { IVideoItem } from '../../models/videos.model';
import styles from './videos-container.module.scss';
import VideoTag from '../home/videos-block/video-tag';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faEye, faThumbsUp, faThumbsDown } from '@fortawesome/free-solid-svg-icons';
import moment from 'moment';
import dynamic from 'next/dynamic';

const ReactPlayer = dynamic(
    () => import('react-player'),
    { loading: () => <p>...</p>, ssr: false }
)
  

export default function VideoContainer({data} :IVideosPageProp){
    const videoInfo:IVideoItem = data;
    const videoTag = [{"tagName": "Foo", "tagId": 1}]
    const fallBackElement = () => {
        return <img src={videoInfo.default_thumbnail_url} width="100%"/>
    }

    return (
        <div className={styles['videos-container']}>
            <ReactPlayer
                url={`https://youtu.be/${data.video_id}`}
                controls
                width = "100%"
                light={true}
                playing={true}
                fallback={fallBackElement()}
                config={{
                    youtube: {
                      playerVars: { showinfo: 1 }
                    }
                }}
            />
            <div className={styles['videos-body']}>
                <div className={styles['tag-list-container']}>
                    {videoTag.map((tag, index) =>{
                        return <VideoTag videoTag={tag} key={index}/>
                    })}
                </div>
                <div className={styles['video-title']}>
                    {videoInfo.title}
                </div>
                <Row className={styles['video-numbers']}>
                    <Col md={2} xs={2}><FontAwesomeIcon icon={faEye} className={styles['views-icon']} />{videoInfo.views_count}</Col>
                    <Col md={2} xs={4}>{moment(new Date(videoInfo.published_at)).format('Do MMMM YYYY')}</Col>
                    <Col md={4} xs={2}></Col>
                    <Col md={2} xs={2}><FontAwesomeIcon icon={faThumbsUp} className={styles['views-icon']} />{videoInfo.like_count}</Col>
                    <Col md={2} xs={2}><FontAwesomeIcon icon={faThumbsDown} className={styles['views-icon']} />{videoInfo.dislike_count}</Col>
                </Row>
                <div className={styles['video-description']}>
                    {videoInfo.description}
                </div>
                
            </div>
        </div>
    )
}

interface IVideosPageProp {
    data:IVideoItem
}

当我运行yarn dev页面时,页面加载正常,视频播放器按预期呈现和工作。但是当我运行next buld之后next start,页面正在加载,但播放器没有加载。安装它在页面上显示“正在加载...”消息,我刷新了几次,没有运气。无法理解问题。任何人都可以帮忙吗?

更新 1:页面正在渲染视频标题、视频描述等。但动态导入的视频播放器未渲染。在视频播放器的位置,它显示“正在加载...”。

标签: next.jsserver-side-renderingdynamic-importreact-player

解决方案


不确定是否可以从 node_module 动态加载,如下所示:

const ReactPlayer = dynamic(
    () => import('react-player'),
    { loading: () => <p>...</p>, ssr: false }
)

但是你应该能够通过react-player首先创建一个组件来做到这一点,然后像这样动态导入它:

// create a component named Player.js
import ReactPlayer from 'react-player';

const Player = props => (<ReactPlayer {...props}/>)
export default Player;

// then dynamic import it:
const Player = dynamic(
    () => import('../components/Player'),
    { ssr: false }
  )

// Then use <Player> with the same props

推荐阅读