I am trying to create an in-app chat but i keep stumbling across the same problem in javascript. Inside my useEffect, i make an api call to my backend to GET all the conversations with all the messages included and set that to my records state. Also in my useEffect i have a socket listener that listens to the messages sent inside the chats and would like to update the the last message preview to the new message.
My problem is when i first load the web app and try sending a message i keep getting
TypeError: Cannot read properties of undefined (reading 'Messages')
Here is my code:
useEffect(()=> {
axios
.get('/api/messages/',{headers:{"auth-token":localStorage.getItem('jwtToken')}})
.then(res => {
setRecords(res.data)
})
.catch(err =>
console.log(err)
)
// main socket
const newsocket =io.connect(CONNECTION_PORT)
newsocket.on('connect', msg => {
setSocket(newsocket)
console.log(`Admin ${ADMIN.id} is waiting. socketID: ${newsocket.id}`)
});
newsocket.emit('waiting', ADMIN.id);
newsocket.on("socketListening", (msg) => {
console.log(msg)
try{
const result = records.find(e=>e.id===msg.conversationId) //Error occurs here
console.log(result)
const resultMessages=result.Messages;
const newMessages =[msg,...resultMessages]
result.Messages=newMessages;
result.lastMessage=msg.message;
if(msg.senderId!==ADMIN.id){
result.Recipient=false;
}else{
result.Recipient=true;
}
console.log(result);
const arraywithoutrecord = records.filter(e=>e.id!==msg.conversationId)
setRecords([result,...arraywithoutrecord])
}catch(e){
console.log(e)
}
})
return(()=>newsocket.close());
},[]);
CodePudding user response:
Seems like creating a useEffect that subscribes to your "records" state would do the job.
Setting a state in react can be seen as a async function, thus why you get an undefined error
import { useEffect, useState } from 'react';
import axios from 'axios';
const Component = () => {
const [records, setRecords] = useState(null);
const [socket, setSocket] = useState(null);
const CONNECTION_PORT = 1234;
let myMsg;
const newsocket = io.connect(CONNECTION_PORT);
// First useEffect (called on init) :
useEffect(() => {
axios
.get('/api/messages/', { headers: { 'auth-token': localStorage.getItem('jwtToken') } })
.then(res => {
setRecords(res.data);
})
.catch(err =>
console.log(err)
);
// main socket
newsocket.on('connect', msg => {
// Set to component variable
myMsg = msg;
setSocket(newsocket);
console.log(`Admin ${ADMIN.id} is waiting. socketID: ${newsocket.id}`);
});
newsocket.emit('waiting', ADMIN.id);
newsocket.on('socketListening', (msg) => {
console.log(msg);
}, []);
// Second useEffect (called every time "records" state is updated):
useEffect(() => {
try {
const result = records.find(e => e.id === myMsg['conversationId']); //Error occurs here
console.log(result);
const resultMessages = result.Messages;
const newMessages = [myMsg, ...resultMessages];
result.Messages = newMessages;
result.lastMessage = myMsg.message;
if (myMsg['senderId'] !== ADMIN.id) {
result.Recipient = false;
} else {
result.Recipient = true;
}
const arraywithoutrecord = records.filter(e => e.id !== myMsg['conversationId']);
setRecords([result, ...arraywithoutrecord]);
} catch (e) {
console.error(e);
}
});
return (() => newsocket.close());
}, [records]);
return (
<></>
);
};
CodePudding user response:
records does not contain the message your are looking for. Probably it is because data are not loaded yet.
try set logs and check: what is executing first: thenLog or socketListeningLog?
.then(res => {
console.log("getting is done");
setRecords(res.data)
})