I have the following react component
function ConferencingRoom() {
const [participants, setParticipants] = useState({})
console.log('Participants -> ', participants)
useEffect(() => {
// messages handlers
socket.on('message', message => {
console.log('Message received: ' + message.event)
switch (message.event) {
case 'newParticipantArrived':
receiveVideo(message.userid, message.username)
break
case 'existingParticipants':
onExistingParticipants(
message.userid,
message.existingUsers
)
break
case 'receiveVideoAnswer':
onReceiveVideoAnswer(message.senderid, message.sdpAnswer)
break
case 'candidate':
addIceCandidate(message.userid, message.candidate)
break
default:
break
}
})
return () => {}
}, [participants])
// Socket Connetction handlers functions
const onExistingParticipants = (userid, existingUsers) => {
console.log('onExistingParticipants Called!!!!!')
//Add local User
const user = {
id: userid,
username: userName,
published: true,
rtcPeer: null
}
setParticipants(prevParticpants => ({
...prevParticpants,
[user.id]: user
}))
existingUsers.forEach(function(element) {
receiveVideo(element.id, element.name)
})
}
const onReceiveVideoAnswer = (senderid, sdpAnswer) => {
console.log('participants in Receive answer -> ', participants)
console.log('***************')
// participants[senderid].rtcPeer.processAnswer(sdpAnswer)
}
const addIceCandidate = (userid, candidate) => {
console.log('participants in Receive canditate -> ', participants)
console.log('***************')
// participants[userid].rtcPeer.addIceCandidate(candidate)
}
const receiveVideo = (userid, username) => {
console.log('Received Video Called!!!!')
//Add remote User
const user = {
id: userid,
username: username,
published: false,
rtcPeer: null
}
setParticipants(prevParticpants => ({
...prevParticpants,
[user.id]: user
}))
}
//Callback for setting rtcPeer after creating it in child component
const setRtcPeerForUser = (userid, rtcPeer) => {
setParticipants(prevParticpants => ({
...prevParticpants,
[userid]: { ...prevParticpants[userid], rtcPeer: rtcPeer }
}))
}
return (
<div id="meetingRoom">
{Object.values(participants).map(participant => (
<Participant
key={participant.id}
participant={participant}
roomName={roomName}
setRtcPeerForUser={setRtcPeerForUser}
sendMessage={sendMessage}
/>
))}
</div>
)
}
the only state it has is a hashTable of participants inside the call using useState hook to define it.
then I'm using useEffect to listen on the socket events for the chat room just 4 events
then After that, I'm defining the 4 callback handlers for those events with respect to there order of execution on the server
and last I have another callback function that gets passed to every child participant in the list so that after the child component creates its rtcPeer object it send it to the parent to set it on the participant object in the participant's hashTable
The flow goes like this participants join the room -> existingParticipants event gets called -> local participant gets created and added to the participants hashTable then -> recieveVideoAnswer and candidate gets emitted by the server multiple time as you can see in the screenshot
the first event the state is empty the subsequent two events its there then it's empty again and this pattern keeps repeating one empty state then the following two is correct and I have no idea what's going on with the state
useEffect
, so you will create a new listener for every render. Is that really what you want? It's also a good idea to return a cleanup function from the function given touseEffect
so that the listener will be removed when theConferencingRoom
component is unmounted. – Abrasion...participants
instead of...prevParticipants
. – Aspirateconsole.log
at the beginning of your message handler is meaningless — it is always going to log the initial state (so long as your dependency array is correct), but the functional update syntax in the other methods will receive the current state. – Aspirate