我正在尝试使用 React、Express、Socket.io 和 Webrtc 构建 Microsoft 团队克隆。
以下是通过 react router Link 渲染的 MeetPage 功能组件的代码。
组件未按预期运行,出现本地视频流但未建立套接字连接,我收到以下警告。
警告:无法对已卸载的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏。要解决此问题,请取消 useEffect 清理函数中的所有订阅和异步任务。
我是 React 的新手。我尝试阅读其他类似的问题,但仍然无法解决我的代码的问题。
import React, { useEffect, useRef, useState } from 'react'
import {useHistory} from 'react-router-dom'
import Messenger from './MeetPageComponents/Messenger'
import ParticipantsPanel from './MeetPageComponents/ParticipantsPanel'
import { CopyToClipboard } from "react-copy-to-clipboard"
import Peer from "simple-peer"
import io from "socket.io-client"
import TextField from "@material-ui/core/TextField"
import './meetpage.css'
import {FaVideo} from 'react-icons/fa'
import {FaVideoSlash} from 'react-icons/fa'
import {IoMdMic} from 'react-icons/io'
import {IoMdMicOff} from 'react-icons/io'
import {IoShareOutline} from 'react-icons/io5'
import {BsChatDots} from 'react-icons/bs'
import {HiUsers} from 'react-icons/hi'
import {ImPhoneHangUp} from 'react-icons/im'
import {VscClose} from 'react-icons/vsc'
import {IoShareSocialOutline} from 'react-icons/io5'
import './MeetPageComponents/callingbar.css'
import useTimer from '../hooks/useTimer';
import { formatTime } from '../utils/formatTime';
const socket = io.connect('http://localhost:5000')
function MeetPage() {
// let history = useHistory();
const [ me, setMe ] = useState("")
const [ stream, setStream ] = useState()
const [ receivingCall, setReceivingCall ] = useState(false)
const [ caller, setCaller ] = useState("")
const [ callerSignal, setCallerSignal ] = useState()
const [ callAccepted, setCallAccepted ] = useState(false)
const [ idToCall, setIdToCall ] = useState("")
const [ callEnded, setCallEnded] = useState(false)
const [ name, setName ] = useState("")
const [ callerName, setCallerName ] = useState("")
const myVideo = useRef()
const userVideo = useRef()
const connectionRef= useRef()
const [ isMute, setIsMute] = useState(false)
const [ isVideoOff, setIsVideoOff] = useState(false)
const [ inviteModal,setInviteModal ] = useState(true)
const [ inviteBtnText,setInviteBtnText ] = useState('Send invite')
const [ messengerOpen, setMessengerOpen] = useState(false)
const [ meetCodeText, setMeetCodeText ] = useState('Get your meeting ID to share')
const { timer, handleStart, handleReset } = useTimer(0)
function handleInviteModalClose() {
setInviteModal(!inviteModal);
setInviteBtnText('Send invite')
setMeetCodeText('Get your meeting ID to share')
}
function handleInviteBtnClick() {
setInviteBtnText('Invite sent')
}
function handleMessengerOpen() {
setMessengerOpen(!messengerOpen)
}
function handleMeetCodeChange() {
setMeetCodeText('Meeting code copied to clipboard')
}
function handleIsMute() {
setIsMute(!isMute)
}
function handleIsVideoOff() {
setIsVideoOff(!isVideoOff)
}
useEffect(() => {
navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then((stream) => {
setStream(stream)
myVideo.current.srcObject = stream
})
socket.on("me", (id) => {
// handleStart();
setMe(id);
// console.log(me);
console.log(id);
})
socket.on("callUser", (data) => {
setReceivingCall(true)
setCaller(data.from)
setCallerName(data.name)
setCallerSignal(data.signal)
})
}, [])
const callUser = (id) => {
const peer = new Peer({
initiator: true,
trickle: false,
stream: stream
})
peer.on("signal", (data) => {
socket.emit("callUser", {
userToCall: id,
signalData: data,
from: me,
name: name
})
})
peer.on("stream", (stream) => {
userVideo.current.srcObject = stream
})
socket.on("callAccepted", (signal) => {
setCallAccepted(true)
peer.signal(signal)
})
connectionRef.current = peer
}
const answerCall =() => {
setCallAccepted(true)
const peer = new Peer({
initiator: false,
trickle: false,
stream: stream
})
peer.on("signal", (data) => {
socket.emit("answerCall", { signal: data, to: caller })
})
peer.on("stream", (stream) => {
userVideo.current.srcObject = stream
})
peer.signal(callerSignal)
connectionRef.current = peer
}
const leaveCall = () => {
setCallEnded(true)
connectionRef.current.destroy()
handleReset()
}
return (
<div className="meet-page-main">
<div className="video-cont">
<div className="first-video-container">
{/* <div className="first-username">{name}</div> */}
{stream && <video className="first-user-vid" playsInline muted ref={myVideo} autoPlay/>}
</div>
{callAccepted && !callEnded ?
<div className="second-video-container">
{/* <div className="second-username">{callerName}</div> */}
<video className="second-user-vid" playsInline muted ref={userVideo} autoPlay />
</div>: null}
</div>
{inviteModal &&
<div className="invite-modal">
<div className="invite-modal-header">
<p className="invite-heading">Invite someone to join you</p>
<VscClose style={{cursor:"pointer"}} onClick={handleInviteModalClose}/>
</div>
<TextField
id="filled-secondary"
label="Your name"
variant="filled"
spellCheck='false'
value={name}
onChange={(e) => setName(e.target.value)}
style={{backgroundColor:"white",borderRadius:"5px",marginBottom:"10px"}}
/>
<TextField
id="filled-secondary"
label="ID to be invited"
variant="filled"
spellCheck='false'
value={idToCall}
style={{backgroundColor:"white",borderRadius:"5px"}}
onChange={(e) => setIdToCall(e.target.value)}
/>
<button className="invite-btn" onClick={() => {callUser(idToCall);handleInviteBtnClick()}}>{inviteBtnText}</button>
<div className="or-div">OR</div>
<CopyToClipboard text={me}>
<button className="share-id-btn" onClick={handleMeetCodeChange}>{meetCodeText}</button>
</CopyToClipboard>
</div>
}
{receivingCall && !callAccepted ? (
<div className="caller">
<h1 >{callerName|| 'Someone'} is calling...</h1>
<button className="invite-btn" onClick={answerCall}>
Let in
</button>
</div>
) : null}
<div className="calling-bar">
<div className="timer">{formatTime(timer)}</div>
{isVideoOff ?
<button className="calling-bar-icon" onClick={handleIsVideoOff}><FaVideoSlash /></button>
: <button className="calling-bar-icon" onClick={handleIsVideoOff}><FaVideo /></button>
}
{isMute ?
<button className="calling-bar-icon" onClick={handleIsMute}><IoMdMicOff /></button>
: <button className="calling-bar-icon" onClick={handleIsMute}><IoMdMic /></button>
}
<div className="calling-bar-icon"><IoShareOutline /></div>
<button className="calling-bar-icon" onClick={handleInviteModalClose}><IoShareSocialOutline /></button>
<button className="calling-bar-icon bar-section-two" onClick={handleMessengerOpen}>
<BsChatDots />
<span className="new-message-dot"></span>
</button>
<div className="calling-bar-icon bar-section-two"><HiUsers /></div>
{callAccepted && !callEnded ?
(<button className="calling-bar-icon bar-section-three" onClick={leaveCall}>
<ImPhoneHangUp />
</button>)
:(
<button className="calling-bar-icon bar-section-three">
<ImPhoneHangUp />
</button>
)}
</div>
{ messengerOpen && <Messenger func={handleMessengerOpen} />}
<ParticipantsPanel />
</div>
)
}
export default MeetPage