Home > Back-end >  Socket.io data spamming the console until the Payload is too large
Socket.io data spamming the console until the Payload is too large

Time:02-01

The following code is part of a chat application build with react native which is working via a socket.io server.

const Message = ({text, isSent}) => {
  return (
    <View style={[styles.messageContainer, isSent ? styles.sentMessage : styles.receivedMessage]}>
      <Text style={styles.messageText}>{text}</Text>
    </View>
  )
}

export const ChatScreen = ({ route }) => {

  const {control, handleSubmit, reset} = useForm();
  const socket = useContext(SocketContext)
  const { user } = route.params;

  const onSendPress = async(data) => {

    const message = data.messageInput
    const uuid = await AsyncStorage.getItem('uuid')


    if(message === '') return

    console.log('Message Send: '   message   ' | to: '   user.uuid)
    addMessage(message, true);
    reset();

    socket.emit('send-chat-message', {
      message: message,
      sender: uuid,
      recipient: user.uuid
    })

  }

  socket.on('receive-chat-message', async(data) => {
    console.log(data)

    if(data.sender !== user.uuid) return

    addMessage(data.message, false)

  })

  const [messages, setMessages] = useState([
    { text: 'Hello! How can I help you today?', isSent: false },
    { text: 'Hi! I was wondering if you could give me some advice.', isSent: true },
    { text: 'Of course! I would be happy to help.', isSent: false },
  ]);

  const scrollViewRef = useRef(null);

  const addMessage = (text, isSent) => {
    setMessages([...messages, { text, isSent }]);

    scrollViewRef.current.scrollToEnd({ animated: true });
  };


  return (
    <View style={styles.background}>

      <StatusBar style="auto" />

      <ScrollView style={styles.container} ref={scrollViewRef}>
        {messages.map((message, index) => (
          <Message key={index} text={message.text} isSent={message.isSent} />
        ))}
      </ScrollView>

      <KeyboardAvoidingView behavior='padding' keyboardVerticalOffset={55} style={styles.bottomTextInput}>

        <Controller
          name={'messageInput'}
          control={control}
          render={({field: {value = '', onChange, onBlur}}) => (
            <>
              <View style={styles.input}>
                <TextInput 
                  style={{paddingHorizontal: 11, paddingTop: 2}}
                  onChangeText={onChange}
                  onBlur={onBlur}
                  value={value}
                  multiline={true}
                  fontSize={17}
                />
              </View>

              <TouchableOpacity onPress={handleSubmit(onSendPress)} style={[styles.sendInput, { backgroundColor: value === '' ? '#cacaca' : '#858AE3'}]}>
                <Ionicons 
                  name={'paper-plane'} 
                  size={20} 
                  color={'white'} />
              </TouchableOpacity>
            </>
          )}
        />

      </KeyboardAvoidingView>

    </View>
  )
}

Now everything is working quite well, the only problem I'm running into is that somehow the data I receive with the receive-chat-message event is doubling each time a new message comes in. To make it visual, this is my console after three different messages:

{"message": "First Message", "recipient": "7fa68f52-ad00-4bdd-9cfc-2af2e15d8d8d", "sender": "2bfe33f0-4882-4ff6-a9ac-4356cd3e7a66"} 
{"message": "Second Message", "recipient": "7fa68f52-ad00-4bdd-9cfc-2af2e15d8d8d", "sender": "2bfe33f0-4882-4ff6-a9ac-4356cd3e7a66"} 
{"message": "Second Message", "recipient": "7fa68f52-ad00-4bdd-9cfc-2af2e15d8d8d", "sender": "2bfe33f0-4882-4ff6-a9ac-4356cd3e7a66"} 
{"message": "Third Message", "recipient": "7fa68f52-ad00-4bdd-9cfc-2af2e15d8d8d", "sender": "2bfe33f0-4882-4ff6-a9ac-4356cd3e7a66"} 
{"message": "Third Message", "recipient": "7fa68f52-ad00-4bdd-9cfc-2af2e15d8d8d", "sender": "2bfe33f0-4882-4ff6-a9ac-4356cd3e7a66"} 
{"message": "Third Message", "recipient": "7fa68f52-ad00-4bdd-9cfc-2af2e15d8d8d", "sender": "2bfe33f0-4882-4ff6-a9ac-4356cd3e7a66"} 
{"message": "Third Message", "recipient": "7fa68f52-ad00-4bdd-9cfc-2af2e15d8d8d", "sender": "2bfe33f0-4882-4ff6-a9ac-4356cd3e7a66"}

I checked if the server is really just getting one request at a time and it is like this. The server is only getting one request and is also only emitting one request to the client who is receiving the message.

I appreciate any help since the problem is literally bugging me out.

CodePudding user response:

Most likely error is due to you are calling socket.on('receive-chat-message', ...) directly in component body, that means that every time component is rerendered - this line is executed, so you have multiple listeners in same component executing same code on this event, as you can see - every time you call setMessages - component is rerendered, additional listener is added and you are getting 1 more duplicate.

Solution: Wrap it with useEffect:

useEffect(() => {
  if (!user?.uuid) return;

  const fn = async (data) => {
    console.log(data);
    if (data.sender !== user.uuid) return;
    addMessage(data.message, false);
  };

  socket.on("receive-chat-message", fn);

  return () => {
    socket.off("receive-chat-message", fn);
  };
}, [socket, user?.uuid]);

Possible error #2 - setMessages([...messages, { text, isSent }]);. Here you can get errors due to closures, prefered to use functional state setter:

setMessages(messages => [...messages, { text, isSent }]);
  • Related