Ref返回null,但是不是(null)吗?

时间:2019-09-21 19:19:28

标签: reactjs

我正在尝试制作一个反应视频播放器。 视频加载得很好,当我按播放时,它会被播放,依此类推。 当我想显示它的持续时间时发生麻烦。 我尝试通过ref访问它。它获取视频,但是ref返回null?我正在控制台记录,其中包括持续时间。 这是一张图片: enter image description here

要添加:我在componentDidMount()中调用ref只是为了查看它是否已被“捕获”。 这是代码:

import React from 'react';
import ReactDOM from 'react-dom';

class Show extends React.Component {

    constructor(props) {

        super(props);
        this.state = {
            video: "",
            switch: false,
            remaining: null,
        };
        this.playPause = this.playPause.bind(this);
        this.videoRef = React.createRef();
        this.trackTime = this.trackTime.bind(this);
        this.volume = this.volume.bind(this);
        this.fullScreen = this.fullScreen.bind(this);

    }

    fullScreen(){

        let elem = this.videoRef.current;
        if (elem.requestFullscreen){
            elem.requestFullscreen();
          } 
          else if (elem.mozRequestFullScreen){ /* Firefox */
            elem.mozRequestFullScreen();
          } 
          else if (elem.webkitRequestFullscreen){ /* Chrome, Safari & Opera */
            elem.webkitRequestFullscreen();
          } 
          else if (elem.msRequestFullscreen){ /* IE/Edge */
            elem.msRequestFullscreen();
          }

    }

    volume(e){
        this.videoRef.current.volume = e.target.value/100;
    }

    trackTime(e){
        this.setState({
            remaining: e.target.duration - e.target.currentTime,
        });
    }

    playPause(){

        this.setState({
            switch: !this.state.switch
        });

        if(this.videoRef.current.paused){
            this.videoRef.current.play();
        }
        else{
            this.videoRef.current.pause();
        }

    }

    componentDidMount(){

        let token = document.querySelector("meta[name='csrf-token']").getAttribute("content");

        let urlId = window.location.href;
        let getaVideoIdId = urlId.lastIndexOf("/");
        let videoId = urlId.substring(getaVideoIdId+1, urlId.length);

        $.ajax({
            url: '/showAjax',
            type: 'POST',
            data: {_token: token , message: "bravo", videoId: videoId},
            dataType: 'JSON',
            success: (response) => { 
                console.log("success");
                //console.log(response);
                this.setState({
                    video: response.video,
                }); 

            },
            error: (response) => {
                console.log("error");
                console.log(response);
            }
        }); 
        console.log(this.videoRef);
        //this.videoRef.current.play();
    }

    render(){
        //console.log(this.state);

        let PlayPause = this.state.switch ? "fa fa-pause-circle" : "fa fa-play-circle";

        let minutes = Math.floor(this.state.remaining/60);
        minutes = (""+minutes).length===1 ? "0"+minutes : minutes;//Checks if mins are one digit by turning it into string that now beasues length, if length is 1(single digit), if it is, then adds zero in front of it.
        let seconds = Math.floor(this.state.remaining%60);
        seconds = (""+seconds).length===1 ? "0"+seconds : seconds;//Same as mins, but for seconds.
        let remainingTime = minutes+" : "+seconds;

        let videoUrl = this.state.video && this.state.video.name ? "/storage/"+this.state.video.user.name+"'s Videos/"+this.state.video.name : null;

        let video = videoUrl ? <div  className={"videoWrapper"}><video ref={this.videoRef} preload="auto" onTimeUpdate={this.trackTime}>
            <source src={videoUrl} type="video/mp4"/>
            <source src={videoUrl} type="video/ogg"/>
            Your browser does not support the video tag.
            </video>
            <div id="controls">

                <button className="btnV" onClick={this.playPause}><i className={PlayPause}></i></button>
                <div className="time">{remainingTime}</div>
                <input type="range" className="custom-range" id="customRange" name="points1" onChange={this.volume}/>
                <div className="time" onClick={this.fullScreen}><i className="fa fa-expand"></i></div>

            </div>
        </div> : "";

        return (
            <div className="container">
                {video}
            </div>
        );

    }

}

if(document.getElementById('show')){

    ReactDOM.render(<Show/>, document.getElementById('show'));

}

Edit1:另外,刷新页面时autoPlay并不总是起作用...并显示“未捕获(承诺)DOMException”。

1 个答案:

答案 0 :(得分:1)

componentDidMount()在安装组件后立即被调用。

在调用componentDidMount()之前,将调用render()来初始化DOM。

但是,在render()中,您的操作如下:

let videoUrl = this.state.video
   && this.state.video.name ? "/storage/"+this.state.video.user.name+"'s Videos/"+this.state.video.name : null;

let video = videoUrl ? <div  className={"videoWrapper"}><video ref={this.videoRef} preload="auto" onTimeUpdate={this.trackTime}>

在第一个render()处,videoUrl可能为false,因为state.video尚未初始化。

这意味着this.videoRef不会在此渲染功能中初始化。

现在是null

然后轮到componentDidMount()了。

componentDidMount(),您获取了视频并启动了state.video

因此将调用下一个render()。并且this.videoRef也将被初始化,但不会在componentDidMount()中被初始化。

这就是为什么您的console.log显示null的原因。

this.videoRef将按照以下步骤进行初始化。

  1. 第一个渲染函数被调用。

    this.state.video->“”

    this.videoRef->空

  2. componentDidMount调用

    this.state.video->有效的内容。

    this.videoRef->空

  3. 另一个渲染功能,用于更新名为this.state.video的视频

    this.videoRef->有效的内容。

编辑:在this.videoRef中首次初始化有效的componentDidUpdate()时,您可以访问它。

componentDidUpdate(prevProps, prevState) {
  if(prevState.video !== this.state.video) { // this.state.video is updated
     // That is the place where you can access into valid this.videoRef
  }
}