将视频流 javascript 代码传输到 React (ML5)
Transferring video streaming javascript code into React (ML5)
我尝试将ML5图像分类示例(Link)中的代码转换为我的React组件,如下所示:
class App extends Component {
video = document.getElementById('video');
state = {
result :null
}
loop = (classifier) => {
classifier.predict()
.then(results => {
this.setState({result: results[0].className});
this.loop(classifier) // Call again to create a loop
})
}
componentDidMount(){
ml5.imageClassifier('MobileNet', this.video)
.then(classifier => this.loop(classifier))
}
render() {
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
this.video.srcObject = stream;
this.video.play();
})
return (
<div className="App">
<video id="video" width="640" height="480" autoplay></video>
</div>
);
}
}
export default App;
但是这不起作用。错误消息说 Unhandled Rejection (TypeError): Cannot set property 'srcObject' of null
.
我可以想象 video = document.getElementById('video');
可能无法通过 id 抓取元素。所以我尝试了
class App extends Component {
video_element = <video id="video" width="640" height="480" autoplay></video>;
...
render() {
...
return (
<div className="App">
{video_element}
</div>
);
}
}
这也没有用。我对实现它的正确方法感到困惑?
感谢任何帮助,谢谢!
在实例化 App
的那一刻,视频元素尚不存在,但 document.getElementById
运行,返回未定义或 null。这就是为什么你得到:
Cannot set property 'srcObject' of null
因为这里:
this.video.srcObject = stream
this.video
为空。
这不是正确的做法。您应该准备 dom 元素的引用,将其分配为道具,然后从那里访问该元素。类似于:
class App extends Component {
video = React.createRef()
...
render() {
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
if ( this.video.current ) {
this.video.current.srcObject = stream;
this.video.current.play();
}
})
return (
...
<video ref={ this.video }
id="video"
width="640"
height="480"
autoplay
/>
我再次回答的是一个略有不同的问题,而不是 ref
。
有一个巨大的问题导致可怕的闪烁和由于异常而不断失败的承诺...这是在渲染方法中获取用户媒体!
考虑一下,每次设置状态时,都会重新渲染组件。您有一个不断更新组件状态的循环,但该承诺一直失败。
您需要在安装组件时获取用户媒体:
componentDidMount() {
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
if (this.video.current) {
this.video.current.srcObject = stream;
this.video.current.play();
}
ml5.imageClassifier("MobileNet", this.video.current)
.then(classifier => this.loop(classifier));
});
}
你的渲染方法会更短:
render() {
return (
<div className="App">
<video ref={this.video} id="video" width="640" height="480" autoPlay />
</div>
)
}
我尝试将ML5图像分类示例(Link)中的代码转换为我的React组件,如下所示:
class App extends Component {
video = document.getElementById('video');
state = {
result :null
}
loop = (classifier) => {
classifier.predict()
.then(results => {
this.setState({result: results[0].className});
this.loop(classifier) // Call again to create a loop
})
}
componentDidMount(){
ml5.imageClassifier('MobileNet', this.video)
.then(classifier => this.loop(classifier))
}
render() {
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
this.video.srcObject = stream;
this.video.play();
})
return (
<div className="App">
<video id="video" width="640" height="480" autoplay></video>
</div>
);
}
}
export default App;
但是这不起作用。错误消息说 Unhandled Rejection (TypeError): Cannot set property 'srcObject' of null
.
我可以想象 video = document.getElementById('video');
可能无法通过 id 抓取元素。所以我尝试了
class App extends Component {
video_element = <video id="video" width="640" height="480" autoplay></video>;
...
render() {
...
return (
<div className="App">
{video_element}
</div>
);
}
}
这也没有用。我对实现它的正确方法感到困惑?
感谢任何帮助,谢谢!
在实例化 App
的那一刻,视频元素尚不存在,但 document.getElementById
运行,返回未定义或 null。这就是为什么你得到:
Cannot set property 'srcObject' of null
因为这里:
this.video.srcObject = stream
this.video
为空。
这不是正确的做法。您应该准备 dom 元素的引用,将其分配为道具,然后从那里访问该元素。类似于:
class App extends Component {
video = React.createRef()
...
render() {
navigator.mediaDevices.getUserMedia({ video: true })
.then((stream) => {
if ( this.video.current ) {
this.video.current.srcObject = stream;
this.video.current.play();
}
})
return (
...
<video ref={ this.video }
id="video"
width="640"
height="480"
autoplay
/>
我再次回答的是一个略有不同的问题,而不是 ref
。
有一个巨大的问题导致可怕的闪烁和由于异常而不断失败的承诺...这是在渲染方法中获取用户媒体!
考虑一下,每次设置状态时,都会重新渲染组件。您有一个不断更新组件状态的循环,但该承诺一直失败。
您需要在安装组件时获取用户媒体:
componentDidMount() {
navigator.mediaDevices.getUserMedia({ video: true }).then(stream => {
if (this.video.current) {
this.video.current.srcObject = stream;
this.video.current.play();
}
ml5.imageClassifier("MobileNet", this.video.current)
.then(classifier => this.loop(classifier));
});
}
你的渲染方法会更短:
render() {
return (
<div className="App">
<video ref={this.video} id="video" width="640" height="480" autoPlay />
</div>
)
}