Search code examples
javascriptreactjssdkchatpubnub

React Pubnub Chat. Message dublication or no message at all


I have persisting problem in my React website. We are using the pubnub SDK to create a chat component, so people can chat with eachother. All the channel management is done, but the problem is that all the messages get dublicated every time i switch the channel, and they only get dublicated in the Dom. PubNub's history API returns only one message, but only after refresh, because the component fetches history messages only on mount, or on channel change.

Here is the code, that is responsible for the messages

export default function Chat({ chatRoom, person, task }) {
  const [messages, addMessage] = useState([]); //messages that are being mapped in the JSX
  const [message, setMessage] = useState("");//set by the input field in the JSX


//adding the pubnub listeners on mount
  useEffect(() => {
    console.log("ADDING LISTENER");

    pubnub.addListener({
      message: (message) => {
        if (message) {
          addMessage((messages) => [...messages, message]);
          console.log(message.message);
        }
        scrollingComponent.current.scrollIntoView({ behavior: "smooth" });
      },
      file: handleFile,
    });

    pubnub.subscribe({ channels: [chatRoom] });

//cleaning listeneres on dismount
    return function cleanup() {
      pubnub.removeListener({
        message: (message) => {
          if (message) {
            addMessage((messages) => [...messages, message]);
            console.log(message.message);
          }
          scrollingComponent.current.scrollIntoView({ behavior: "smooth" });
        },
        file: handleFile,
      });

      pubnub.unsubscribeAll();
      addMessage([]);
    };
  }, [chatRoom]);



//added this function and it's coresponding useEffect just to test if thats the cause of the dublication. Before that the function sendMessage had the body of the use effect
const sendMessage = (m) => {
  console.log(m);
  setMessage("");
};

  useEffect(() => {
    if (message) {
      pubnub
        .publish({
          channel: chatRoom,
          message: message,
          storeInHistory: true,
        })
        .then(() => {
          pubnub.signal({
            channel: chatRoom,
            message: "notification",
          });
          pubnub.signal({
            channel: chatRoom,
            message: "not_typing",
          });
        })
        .catch((error) =>
          addMessage((messages) => [...messages, error.toString()])
        );
    }
  }, [sendMessage]);

//code continues...

if neccesary, I can post the whole .js file


Solution

  • The problem in your code is that you are not removing the listener properly. You are recreating the same function twice (but its not the same function) so the PubNub SDK won't remove it from the listeners.

    Instead you should do something like this in the first useEffect:

    //adding the pubnub listeners on mount
    useEffect(() => {
      const listener = { // <-- extract the listener
        message: (message) => {
          if (message) {
            addMessage((messages) => [...messages, message]);
            console.log(message.message);
          }
          scrollingComponent.current.scrollIntoView({ behavior: "smooth" });
        },
        file: handleFile,
      }
      
    
      pubnub.addListener(listener); // <-- pass the listener here
    
      pubnub.subscribe({ channels: [chatRoom] });
      
      return function cleanup() {
        pubnub.removeListener(listener); // <-- pass the same listener here
    
        pubnub.unsubscribeAll();
        addMessage([]);
      };
    }, [chatRoom]);