无法修复警告:无法对已卸载的组件执行 React 状态更新。这是一个空操作,但它表明您的应用程序中存在内存泄漏

时间:2021-06-29 16:09:47

标签: reactjs express socket.io webrtc use-effect

我正在尝试使用 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

0 个答案:

没有答案