I am currently following a tutorial from webDevSimplified
youtube : https://www.youtube.com/watch?v=tBr-PybP_9c
github repo : https://github.com/WebDevSimplified/Whatsapp-Clone
I have compared my code with the repo countless times and also read socket.io's documentation but to no avail.
There are already fair a few threads out there with a similar issue but many have been left unanswered or simply have a completely different setup.
I have used yarn package manager for the project instead of npm as shown in the tutorial but I doubt this is the culprit. I have all required dependencies installed.
Let's begin with server.js
const io = require('socket.io')(5000) // I changed it to 3000 but just got a different Error(see title)
io.on('connection', socket => {
const id = socket.handshake.query.id
socket.join(id)
socket.on('send-message', ({ recipients, text }) => {
recipients.forEach(recipient => {
const newRecipients = recipients.filter(r => r !== recipient)
newRecipients.push(id)
socket.broadcast.to(recipient).emit('receive-message', {
recipients: newRecipients, sender: id, text
})
})
})
})
In this app we used useContext
to provide the socket for our components.
Here the socketProvider.js
import React, { useContext, useEffect, useState } from "react";
import io from "socket.io-client";
const SocketContext = React.createContext();
export function useSocket() {
return useContext(SocketContext);
}
export function SocketProvider({ id, children }) {
const [socket, setSocket] = useState();
//console.log(socket)
useEffect(() => {
const newSocket = io("http://localhost:5000", { query: { id } });// I changed the host here as well to 3000 but I either get a POST or a GET error respectively
setSocket(newSocket);
return () => newSocket.close();
}, [id]);
return (
<SocketContext.Provider value={socket}>{children}</SocketContext.Provider>
);
}
Which is then nested in another contextProvider aka ConversationsProvider.js
import React, { useContext, useState, useEffect, useCallback } from "react";
import useLocalStorage from "../hooks/useLocalStorage";
import { useContacts } from "./ContactsProvider";
import { useSocket } from "./SocketProvider";
const ConversationsContext = React.createContext();
export function useConversations() {
return useContext(ConversationsContext);
}
export function ConversationsProvider({ id, children }) {
const [conversations, setConversations] = useLocalStorage("conversations",[]);
const [selectedConversationIndex, setSelectedConversationIndex] = useState(0);
const { contacts } = useContacts();
const socket = useSocket();
function createConversation(recipients) {
setConversations((prevConversations) => {
return [...prevConversations, { recipients, messages: [] }];
});
}
const addMessageToConversation = useCallback(({ recipients, text, sender }) => {
setConversations((prevConversations) => {
let madeChange = false;
const newMessage = { sender, text };
const newConversations = prevConversations.map((conversation) => {
if (arrayEquality(conversation.recipients, recipients)) {
madeChange = true;
return {
...conversation,
messages: [...conversation.messages, newMessage],
};
}
return conversation;
});
if (madeChange) {
return newConversations;
} else {
return [...prevConversations, { recipients, messages: [newMessage] }];
}
});
}, [setConversations])
useEffect(() => {
if(socket == null) return
socket.on('receive-message', addMessageToConversation)
return () => socket.off('receive-message')
},[socket, addMessageToConversation])
function sendMessage(recipients, text) {
socket.emit('send-message', { recipients, text })
addMessageToConversation({ recipients, text, sender: id });
}
const formattedConversations = conversations.map((conversation, index) => {
const recipients = conversation.recipients.map((recipient) => {
const contact = contacts.find((contact) => {
return contact.id === recipient;
});
const name = (contact && contact.name) || recipient;
return { id: recipient, name };
});
const messages = conversation.messages.map(message => {
const contact = contacts.find((contact) => {
return contact.id === message.sender;
})
const name = (contact && contact.name) || message.sender;
const fromMe = id === message.sender
return { ...message, senderName: name, fromMe }
})
const selected = index === selectedConversationIndex;
return { ...conversation, messages, recipients, selected };
});
const value = {
conversations: formattedConversations,
selectedConversation: formattedConversations[selectedConversationIndex],
sendMessage,
selectConversationIndex: setSelectedConversationIndex,
createConversation,
};
return (
<ConversationsContext.Provider value={value}>
{children}
</ConversationsContext.Provider>
);
}
function arrayEquality(a, b) {
if (a.length !== b.length) return false;
a.sort();
b.sort();
return a.every((element, index) => {
return element === b[index];
});
}
I had no prior experience with the websocket.API / socket.io and I have not yet fully understood the workflow. I hope someone might see an error I didn't see/noticed so far.
I believe this react setup is slightly different from the norm as I couldn't find any similar setup online which might have been helpful in solving my issue.
If you feel it might be relevant check the master repo above. My local folder structure as well as the code is identical.
I will try another stack and see if I can get it running with node.js or try out the example from the docs meanwhile.
I found the the reason for the error. I simply missed to run the nodemon script in the server directory.