AppStructure - 将 useRef 对象从 react 服务传递到组件



我正在重组一个组件,我将websocket和WebRTC调用移动到"服务"文件 - 我这样做是因为我需要分离进行这些调用的关注点以及组件的重新渲染和状态。在我将代码移出组件之前,我useRef用于定位视频元素,但现在在分离时,我无法完全弄清楚将local video从服务传递到组件。我应该以某种方式使用回调吗?

非常感谢任何帮助,因为这是我需要完成的大学项目的一部分,非常感谢!

第一个代码块是服务,第二个是组件。

var localVideo;
var localStream;
var remoteVideo;
var peerConnection;
var uuid;
var serverConnection;
var peerConnectionConfig = {
'iceServers': [
{ 'urls': 'stun:stun.stunprotocol.org:3478' },
{ 'urls': 'stun:stun.l.google.com:19302' },
]
};
uuid = createUUID();
serverConnection = new WebSocket('ws://localhost:8444');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: true,
};
localVideo = // USED TO BE ASSIGNED useRef()
remoteVideo = // USED TO BE ASSIGNED useRef()
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(getUserMediaSuccess).catch(errorHandler);
} else {
alert('Your browser does not support getUserMedia API');
}
function getUserMediaSuccess(stream) {
localStream = stream;
localVideo.srcObject = stream; // THIS REQUIRES localvideo
}

//  CALL ONCLICK
export function start(isCaller) {
// CALL CONTACT VIA SOCKET IO
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.ontrack = gotRemoteStream;
peerConnection.addStream(localStream);
if (isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
// ===================================================================
import React, { useRef } from 'react';
import Countdown from './Countdown';
import { makeOutGoing } from '../services/WebSocketService'
import { Button } from 'antd';
import { start } from '../services/CallCallerService'
function CallPaneCaller(props) {
console.log("RENDERRRRRING")
localVideo = useRef(); // HOW TO ACCESS THIS FROM THE SERVICE??
remoteVideo = useRef();
const handleOnClick = () => {
start(true)
makeOutGoing(props)
}
return (
<>
<video autoPlay muted style={{ width: '40%' }} ref={localVideo} />
<video autoPlay style={{ width: '40%' }} ref={remoteVideo} />
<Button onClick={() => handleOnClick} size="large">Start Call</Button>
<Countdown timeData={props}/>
</>
);
}
export default CallPaneCaller;

编辑以根据要求显示其他方法:

下面我需要以与上面相同的方式将remoteVideo分配给组件 JSX 元素,并根据答案显示我遇到的困难。

remoteVideo在函数 start 内部调用的gotRemoteStreams(倒数第二个)函数中分配,因此还有一个范围问题:

var localStream;
var remoteVideo;
var peerConnection;
var uuid;
var serverConnection;
var peerConnectionConfig = {
'iceServers': [
{ 'urls': 'stun:stun.stunprotocol.org:3478' },
{ 'urls': 'stun:stun.l.google.com:19302' },
]
};
uuid = createUUID();
serverConnection = new WebSocket('ws://localhost:8444');
serverConnection.onmessage = gotMessageFromServer;
var constraints = {
video: true,
audio: true,
};
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(constraints).then(getUserMediaSuccess).catch(errorHandler);
} else {
alert('Your browser does not support getUserMedia API');
}
function getUserMediaSuccess(stream) {
localStream = stream;
}
export function setSrcObject(localVideo) {
localVideo.srcObject = localStream;
}
// ===================================================================
//  CALL ONCLICK
export function start(isCaller) {
// CALL CONTACT VIA SOCKET IO
peerConnection = new RTCPeerConnection(peerConnectionConfig);
peerConnection.onicecandidate = gotIceCandidate;
peerConnection.ontrack = gotRemoteStream;
peerConnection.addStream(localStream);
if (isCaller) {
peerConnection.createOffer().then(createdDescription).catch(errorHandler);
}
}
// ===================================================================
function gotMessageFromServer(message) {
if (!peerConnection) start(false);
var signal = JSON.parse(message.data);
// Ignore messages from ourself
if (signal.uuid === uuid) return;
if (signal.sdp) {
peerConnection.setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(function () {
// Only create answers in response to offers
if (signal.sdp.type === 'offer') {
peerConnection.createAnswer().then(createdDescription).catch(errorHandler);
}
}).catch(errorHandler);
} else if (signal.ice) {
peerConnection.addIceCandidate(new RTCIceCandidate(signal.ice)).catch(errorHandler);
}
}
function gotIceCandidate(event) {
if (event.candidate != null) {
console.log('sending')
serverConnection.send(JSON.stringify({ 'ice': event.candidate, 'uuid': uuid }));
}
}
function createdDescription(description) {
console.log('got description');
peerConnection.setLocalDescription(description).then(function () {
serverConnection.send(JSON.stringify({ 'sdp': peerConnection.localDescription, 'uuid': uuid }));
}).catch(errorHandler);
}

function gotRemoteStream(event) {
console.log('got remote stream');
remoteVideo.srcObject = event.streams[0];
}

function errorHandler(error) {
console.log(error);
}

我的组件已经开始以相同的方式设置,但不确定如何在服务端处理它:

import React from 'react';
import Countdown from './Countdown';
import { makeOutGoing } from '../services/WebSocketService'
import { Button } from 'antd';
import { start, setSrcObject, setSrcObjectRemote } from '../services/CallCallerService'
function CallPaneCaller(props) {
console.log("SENDER")
const handleOnClick = () => {
start(true)
makeOutGoing(props)
}
return (
<>
<video autoPlay muted style={{ width: '40%' }} ref={localVideo => setSrcObject(localVideo)} />
<video autoPlay style={{ width: '40%' }} ref={remoteVideo => setSrcObjectRemote(remoteVideo)} />
<Button onClick={handleOnClick} size="large">Start Call</Button>
<Countdown timeData={props}/>
</>
);
}
export default CallPaneCaller;


一种选择是使用ref属性的回调形式,以便您可以在 ref 更改为保存流的localStream变量时设置srcObject。为此,请从服务中导出setSrcObject函数。

<video autoPlay muted style={{ width: '40%' }} ref={video => setSrcObject(video)} />

/* service */
export function setSrcObject(video) {
video.srcObject = localStream;
}
function getUserMediaSuccess(stream) {
localStream = stream;
// localVideo.srcObject = stream; // <--- no longer needed as it is handled by the callback above.
}

其他选项是将useRef中创建的 ref 传递给服务

export function setLocalVideoRef(ref){
localVideo = ref
localVideo.current && localVideo.current.srcObject = localStream
}
function getUserMediaSuccess(stream) {
localStream = stream;
localVideo && localVideo.current && localVideo.current.srcObject = stream; // <--- Remains as is
}

...
localVideo = useRef();
setLocalVideoRef(localVideo)

要对远程流进行寻址,您可以创建一个remoteStream变量并保留流,直到调用setSrcObjectRemote()

let localStream;
let remoteSream;
function gotRemoteStream(event) {
console.log('got remote stream');
remoteStream = event.streams[0];
}
export function setSrcObjectRemote(video) {
video.srcObject = remoteStream;
}

最新更新