【问题标题】:How to pass a HTML element to react component?如何将 HTML 元素传递给反应组件?
【发布时间】:2020-08-11 02:48:48
【问题描述】:

这是我的父组件代码片段:

import Card  from 'react-bootstrap/Card';
import React ,{Component}  from 'react';
import MuteButton from './buttons/muteButton/MuteButton';

import './MediaPlayer.css'
class MediaPlayer extends Component {
    constructor(props) {
        super(props);
        this.handleMute=(()=>{
            //console.log(this.muteBtn);
            this.muteBtn.toggle(this.videoTag);
        })        
       
    }
    render() {
        return (
            <Card className="h-100 rounded">
                <video 
                    autoPlay
                    muted
                    className="card-body p-0 rounded w-100"
                    ref={instance => { this.videoTag = instance; }}>
                        <source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"></source>
                </video>
                <div className="playerOverlay p-1">
                    <div className="center text-white">
                    </div>
                    <div className="bg-secondary collapse controlBar p-1 rounded show text-white">
                        <div className="align-items-center d-flex flex-row justify-content-between p-0">
                            <MuteButton videoTag={this.videoTag}/>
                            <div><span ref={instance=>{this.elapseTimeSpan=instance;}}>00:00:00</span></div>
                        </div>

这是我的孩子代码:

import React ,{Component,Fragment}  from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import '../Button.css';
class MuteButton extends Component {
    constructor(props) {
        super(props);
        var muted=true;
        this.state={"muted":muted};
        this.videoTag=this.props.videoTag;
        this.mutedSvg=(
            <Fragment>
                <svg 
                    xmlns="http://www.w3.org/2000/svg" 
                    width="24" 
                    height="24" 
                    style={{"fill": "white"}} viewBox="0 0 24 24">
                        <path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>
                </svg>
            </Fragment>
        );
        this.unMuteSvg=(
            <Fragment>
                <svg xmlns="http://www.w3.org/2000/svg" 
                    width="24" 
                    height="24" 
                    style={{"fill":"white"}} 
                    viewBox="0 0 24 24">";
                    <path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>
                </svg>
            </Fragment>
        )
        this.toggle=(()=>{
            muted=!muted;
            this.videoTag.muted=muted;
            this.setState({"muted":muted});
        })
    }
    render() {
        if (this.state.muted){
            return (
                <div className="btnlink" title="Mute" onClick={this.toggle}> 
                    {this.mutedSvg}
                </div>);
        } else {
            return (
                <div className="btnlink" title="Mute" onClick={this.clickHandler}> 
                    {this.unMuteSvg}
                </div>);
        }

    }
}
export default MuteButton;

我想将视频标签传递给静音按钮组件,以便在单击静音按钮时将视频标签设置为静音/取消静音。

但是,当我单击静音按钮时,我收到以下错误消息。

MuteButton.js:34 Uncaught TypeError: Cannot set property 'muted' of undefined

我该如何解决这个问题?

在得到专家的建议后,我几乎完成了。 静音按钮工作正常,但是,我已将静音设置为 true, 但视频仍未静音。

我在stackBlitz 上创建示例。 你能帮忙检查一下吗?

【问题讨论】:

  • 我会在父级上拥有muted 状态 - 视频所在的位置是 & 而是将一个函数作为设置新状态的道具传递给子级,而不是尝试传递元素并直接改变其属性
  • 你的意思是我应该操作父组件中的视频标签吗?
  • 阅读https://reactjs.org/docs/refs-and-the-dom.html。这应该让您了解如何获取对 DOM 元素的引用。
  • 是的,你可以在父母上做muted={this.state.muted}
  • @95faf8e76605e973 是正确的,如果您可以仅使用道具获得相同的功能,那是可行的方法。 DOM refs 仅应在您无法使用 props 实现所需功能时使用(通常是布局修改)。

标签: reactjs


【解决方案1】:

无法设置未定义的属性“静音”

从这个answer 和这个article 我们可以了解到,你提供给ref 属性的回调将在组件挂载时执行。但是,您在渲染过程中立即将它传递给子组件,因此它是未定义的,因为该组件尚未安装。为了解决这个问题,您可能可以拥有一个跟踪 refs 的 state,然后挂载:将 refs 分配给 state,以便子组件可以使用分配给其 prop 的正确 ref 重新渲染。

state = {
  videoRef: ""
};

componentDidMount(){
  this.setState({
    videoRef: this.video
  })
}

<video ref={(instance) => (this.video = instance)}>
...

<Child video={this.state.videoRef} />

https://codesandbox.io/s/so-react-html5-video-mute-toggler-using-refs-13srj?file=/src/App.js

此外,Dan Abramov 在answer 上说,只有当它确实被渲染时,才会设置正确的 ref。我会小心使用这个实现。


更好的方法

正如我在评论中指出的那样,将视频静音的更好方法是

在父级上具有静音状态 - 视频所在的位置是 & 将函数作为设置新状态的道具传递给孩子 而不是试图传递元素并改变其属性 直接

state = {
  muted: false
};

toggleMute = () => {
  this.setState({
    muted: !this.state.muted
  });
};

<video muted={this.state.muted}>
...

<Child toggleMute={this.toggleMute} />

代码沙盒:https://codesandbox.io/s/so-react-html5-video-mute-toggler-y6b6q?file=/src/App.js:285-326

【讨论】:

  • 我已经更新了问题,你能帮忙检查一下吗?
  • @TheKNVB 我看了你的 StackBlitz。看起来您正在重新初始化您的构造函数上的状态,从而覆盖以前的状态......来解决这个问题:只需在 1 行中包含所有状态初始化。 this.state={ muted:true, "elapseTime":"00:00:00"};stackblitz.com/edit/react-vzcmhv?file=MediaPlayer.js
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 2015-03-08
  • 2021-05-16
  • 2021-06-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多