开发者问题收集

ReactJS 和 PeerJS (simple-peer) 未捕获(在承诺中)TypeError:无法设置 null 属性(设置‘srcObject’)

2023-02-17
561

我想在我的聊天网络应用中添加一个带有 WebRTC 的视频通话功能。因此,在编写代码后,我测试了代码。-> 没有视频,控制台中出现错误“未捕获(在承诺中)TypeError:无法设置 null 属性(设置'srcObject')” 屏幕截图错误消息

我的代码:

//CallProvider
import React, { createContext, useState, useRef, useEffect } from 'react';
import Peer from 'simple-peer';
import io from 'socket.io-client';

export const VideoCallContext = createContext();

const socket = io('http://localhost:5001');

export function CallProvider({ conv, id, children }) {
  const videoGrid = document.querySelector('#video-grid');
  const [stream, setStream] = useState(null);
  const myVideoRef = useRef(null);
  const peer = new Peer({
    trickle: false,
    stream,
  });
  const peers = {};

  useEffect(() => {
    navigator.mediaDevices
      .getUserMedia({
        video: true,
        audio: true,
      })
      .then((currentStream) => {
        setStream(currentStream);
        myVideoRef.current.srcObject = currentStream.streams[0];
      });

    socket.on('user-connected', (userId) => {
      connectToNewUser(userId, stream);
    });
  });

  socket.on('user-disconnected', (userId) => {
    if (peers[userId]) peers[userId].close();
  });

  function joinCall() {
    peer.on('signal', (data) => {
      socket.emit('join-call', {
        call: conv,
        userId: id,
      });
    });
  }

  function leaveCall() {
    socket.emit('leave-call', {
      call: conv,
      userId: id,
    });
    navigator.mediaDevices.getUserMedia({
      video: false,
      audio: false,
    });
  }

  function connectToNewUser(userId, stream) {
    const call = peer.call(userId, stream);
    const video = document.createElement('video');

    call.on('stream', (userVideoStream) => {
      addVideoStream(video, userVideoStream);
    });

    call.on('close', () => {
      video.remove();
    });
  }

  function addVideoStream(video, stream) {
    video.srcObject = stream;
    video.addEventListener('loadedmetadata', () => {
      video.play();
      video.playsInline = true;
    });
    videoGrid.append(video);
  }

  const value = {
    stream,
    myVideoRef,
    joinCall,
    leaveCall,
  };

  return (
    <VideoCallContext.Provider value={value}>
      {children}
    </VideoCallContext.Provider>
  );
}

// FormCall
//use WebRTC from simplepeer
import React, { useContext } from 'react';
import { Button } from 'react-bootstrap';
import { VideoCallContext } from '../contexts/CallProvider';

export default function FormCall({ id, conv, closeWindow }) {
  const { stream, myVideoRef, joinCall, leaveCall } =
    useContext(VideoCallContext);
  const conversation = conv;

  function closeCall() {
    leaveCall(id);
    closeWindow();
  }

  return (
    <>
      <style>
        {`
          #video-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(210px, 230px));
            grid-auto-rows: auto;
            grid-gap: 5px;
          }
        `}
        {`
          video {
            width: 100%;
            aspect-ratio: 1/1;
            object-fit: cover;
            object-position: center;
            border-radius: 10px;
            overflow: hidden;
          }
        `}
      </style>
      <div className="pb-2" id="video-grid">
        <video playsInline muted ref={myVideoRef} autoPlay></video>
      </div>
      <div className="d-flex flex-row justify-content-around border-top pt-2">
        <Button
          onClick={closeCall}
          className="rounded-circle position-relative"
          style={{ height: '40px', width: '40px' }}
        >
          <i
            className="bi bi-telephone-x-fill position-absolute"
            style={{ left: '28%', top: '20%' }}
          />
        </Button>
      </div>
    </>
  );
}

我安装的软件包是: 软件包

我已经寻找该错误的解决方案。没有什么可以解决我的问题。

我还将“currentStream”更改为“currentStream.streams[0]”,但没有任何变化。

2个回答

当您设置 const myVideoRef = useRef(null) ) 时,您将 myVideoRef.current 设置为 null

如果您需要在 ref 中设置 srcObject 属性:

const myVideoRef = useRef({ srcObject: null })

现在 myVideoRef.current.srcObject 存在并且可以设置。

Wesley LeMahieu
2023-02-17

尝试 const value = { stream:stream, myVideoRef:myVideoRef, joinCall:joinCall, leaveCall:leaveCall, };

另外,我会避免返回 *.Provider 本身。

像这样包装 CallProvider 及其子项:

<VideoCallContext.Provider value={Your value}>
<CallProvider >
<Child1 /> 
<Child2 />
</CallProvider>
</VideoCallContext.Provider>

如果您将 Context.Provider 的实例作为组件返回,则每个状态突变都会重新呈现您的 Context 。 Context 是不必要的。 如果您的 Context 完全包装了依赖的 DOM 片段,那么您的 Context 值是稳定的。

至少要更改这两者之一才能解决您的问题。

P.S. 正如 Wesley LeMahieu 发现的那样,因此我会使用 useRef() 而不是 useRef(null)。

Bujaq
2023-02-17