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

时间:2019-06-09 08:45:08

标签: reactjs

我正在重组一个组件,将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元素,并且答案显示了我遇到的困难。

remoteVideogotRemoteStreams(从底部开始的第二个)函数中分配,该函数在函数开始内部调用,因此还有一个范围问题:

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;




1 个答案:

答案 0 :(得分:0)

一种选择是使用ref属性的回调形式,以便您可以在ref更改为保存流的srcObject变量时随时设置localStream。为此,请从您的服务中导出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中创建的引用传递给服务

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;
}